I got a tar file, after extracting, there are many files naming like
a bc def gh
I want to correct their name into files in sub-directories like
a b/c d/e/f g/h
I face a problem when a variable contains backslash, it will change the original file name. I want to write a script to rename them.
Advertisement
Answer
Parameter expansion is the way to go. You have everything you need in bash
, no need to use external tools like find
.
$ touch a\b c\d\e $ ls -l total 0 -rw-r--r-- 1 ghoti staff 0 11 Jun 23:13 ab -rw-r--r-- 1 ghoti staff 0 11 Jun 23:13 cde $ for file in *\*; do > target="${file//\//}"; mkdir -p "${target%/*}"; mv -v "$file" "$target"; done ab -> a/b cde -> c/d/e
The for loop breaks out as follows:
for file in *\*; do
– select all files whose names contain backslashestarget="${file//\//}";
– swap backslashes for forward slashesmkdir -p "${target%/*}";
– create the target directory by stripping the filename from$target
mv -v "$file" "$target";
– move the file to its new homedone
– end the loop.
The only tricky bit here I think is the second line: ${file//\//}
is an expression of ${var//pattern/replacement}
, where the pattern is an escaped backslash (\
) and the replacement is a single forward slash.
Have a look at man bash
and search for “Parameter Expansion” to learn more about this.
Alternately, if you really want to use find
, you can still take advantage of bash’s Parameter Expansion:
find . -name '*\*' -type f -exec bash -c 't="${0//\//}"; mkdir -p "${t%/*}"; mv -v "$0" "$t"' {} ;
This uses find
to identify each file and process it with an -exec
option that basically does the same thing as the for
loop above. One significant difference here is that find
will traverse subdirectories (limited by the -maxdepth
option), so … be careful.