1

Imagine I have a folder/file structure like the following

a/b/c_d.e
a/b/d.f

I want to mangle the filename so that path separators become _, and between the folder and file is a -, and then that is prepended to the folder location.

a/b/a_b-c_d.e
a/b/a_b-d.f

What I have so far:

find . -type f -name *.c -exec sh -c "echo -n { {} | xargs dirname }; echo -n "/"; realpath --relative-to="$PWD" "{}" | tr '/' '_'" \;

Which will output

./src/ucd-tools/src /src_ucd-tools_src_proplist.c

It seems the first echo -n is adding new lines, but if I manually run echo -n "Hello" it works as expected without new lines.

Red Riding Hood
  • 1,932
  • 1
  • 17
  • 36
  • 1
    You are running `sh`, not `bash`, and `-n` is just another string to print with POSIX `echo`, not a flag. Use `printf '/'` instead. – chepner Nov 11 '17 at 13:16

2 Answers2

4

If you're in bash 4, you have everything you need in the shell itself. No need to use external tools like find.

This could be a one-liner.

$ shopt -s globstar      # This requires bash 4. Lets you use "**"
$ for f in **; do test -f "$f" || continue; d=${f%/*}; echo mv "$f" "$d/${d//\//_}-${f##*/}"; done

Broken out for easier reading:

for f in **; do                       # recurse through directories,
  test -f "$f" || continue            # skipping anything that isn't a file
  d=${f%/*}                           # capture the directory...
  mv -- "$f" "$d/${d//\//_}-${f##*/}"    # and move the file.
done

The "target" on the mv line is made up of the following:

  • $d - the original directory (since files are staying in the same place)
  • ${d//\//_} - uses parameter expansion to replace all slashes with underscores
  • ${f##*/} - strips the dirname, so this is just the filename alone.
chepner
  • 497,756
  • 71
  • 530
  • 681
ghoti
  • 45,319
  • 8
  • 65
  • 104
  • The OP didn't say what the list of file names was being used for, but note that there is the danger (which could be slight) of overwriting data if, using the OP as an example, there were files `./src/ucd_tools/src/proplist.c` and `./src/ucd/tools/src/proplist.c` and you blindly tried to move both to the same target name. – chepner Nov 11 '17 at 13:20
0

just use printf. Its basically like echo but it doesn't print a new line, for example:

computer:~user$echo "hello, world"
hello, world
computer:~user$printf "hello, world"
hello, worldcomputer:~user$echo "hello, world"
Camden
  • 283
  • 2
  • 15