I got a tar file, after extracting, there are many files naming like
a
b\c
d\e\f
g\h
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.
The backslash divides the file name from the path to it, and one directory name from another directory name in a path. You cannot use a backslash in the name for the actual file or directory because it is a reserved character that separates the names into components.
You can also rename a file by using a command in bash script. Many commands exist in Linux to rename a filename. The command 'mv' is the most popular command for renaming a file. There is another command called 'rename' that can also be used for the same task.
Characters to avoid in filenamesYou shouldn't be using slashes or question marks in your filenames. This can cause issues depending on the operating system/file system being used.
We can use the following characters in place of the regular forward-slash (U+002F): U+2044 = Fraction Slash: ⁄ U+2215 = Division Slash: ∕ U+29F8 = Big Solidus: ⧸
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 a\b
-rw-r--r-- 1 ghoti staff 0 11 Jun 23:13 c\d\e
$ for file in *\\*; do
> target="${file//\\//}"; mkdir -p "${target%/*}"; mv -v "$file" "$target"; done
a\b -> a/b
c\d\e -> 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.
Renaming a file with backslashes is simple: mv 'a\b' 'newname'
(just quote it), but you'll need more than that.
You need to:
a\b\c
)a\b
from c
)a/b
, dir b
under dir a
)a\b\c
to file named c
in dir a/b
)Something like this:
#!/bin/bash
find . -name '*\\*' | while read f; do
base="${f%\\*}"
file="${f##*\\}"
path="${base//\\//}"
mkdir -p "$path"
mv "$f" "$path/$file"
done
(Edit: correct handling of filenames with spaces)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With