# Replace slashes in a filename

So I need to write a bash script that copies all files to a specified directory however I need to rename the files to it's absolute path by replacing the / character with __.

For example if the file zad1.sh is in the directory /home/123456/ the file needs to be renamed to __home__123456__zad1.sh

Any ideas on how to do this?

• all files - from where? Add some pseudo-code – RomanPerekhrest Jun 14 '18 at 15:33
• Please, show us what you tried so far. – andcoz Jun 14 '18 at 15:34
• Presuming this is for something, how are you going to handle the case of some__really__important_file.txt when putting things back not going into /path/to/some/really/important_file.txt? – DopeGhoti Jun 14 '18 at 15:40
• @DopeGhoti Good point. For example Python projects might have files named __init__.py, __main__.py, etc. – wjandrea Jun 14 '18 at 20:05

The classic approach would be to use sed:

cp "${filename}" "$(realpath ${filename} | sed s:/:__:g)"  The advantage is primarily portability across shells if you won't necessarily always be using bash. Of course, it also lets you forego the script and just do it with find: find /base/path -type f -exec cp \{\} realpath \{\} | sed s:/:__:g \;  Find has sorting and filtering options you can use if you need them to only copy certain files. edit: That find setup works on one of my systems, but not on the other one. Rather than sort out the difference, I just made it more portable: find /base/path -type f | sed -e "p; s:/:__:g" | xargs -n2 cp  • That find command will not work. The backticks will be evaluated before find and get you basically the equivalent of $PWD/{} with the slashes in $PWD replaced with double underscores. So, if you're in /home/user, this is equivalent to: find /base/path -exec cp {} __home__user__{} \; If you have a file f in /base/path, this will try to copy it to __home__user__/base/path/f. – JoL Jun 14 '18 at 21:04 • @JoL It worked when I tested it... I'll test it again when I get a few minutes... – Perkins Jun 17 '18 at 3:47 • find -exec sh -c 'cp "$1" "$(realpath "$1" | sed s:/:__:g)"' sh {} \; should do – ilkkachu Jun 17 '18 at 17:18
• xargs will have issues with names with whitespace, unless you use find -print0 | sed -z | xargs -0 (with at least GNU sed). Also any of those will make the copies to the current directory, which may or may not be what you want. – ilkkachu Jun 17 '18 at 17:22
• @Perkins "That find setup works on one of my systems" I have a hard time imagining how that could work anywhere. The only edge case I can kind of see is if your current working directory is /base/path and you just have regular files in there, no directories. However, even then you'd be copying to e.g. /base/path/__base__path__./f. That's not right. – JoL Jun 18 '18 at 3:16

To get the path of your file :

realpath <file>


Replace in bash:

echo "${var//search/replace}"  The first two slashes are for making global search. Using just / would only do one replacement. So your code could be path=$(realpath zad1.sh)
path_replaced=${path//\//__}  I believe this will accomplish what you are asking: #!/bin/bash _from_dir=/path/to/files _to_dir=/path/to/dest for file in "${_from_dir}/"*; do
nfile="$(sed 's#/#__#g' <<<"$file")"
cp "$file" "${_to_dir}/$nfile" done  Set the _from_dir variable to the path where your files are located and the _to_dir variable to the path where you want them copied. The loop will go through each file in the _from_dir location. nfile will take the full path of the file and replace / with __. Then it will cp the file into the _to_dir path with a name representing the full path of it's origin. I have done by below method ls -ltr /root/l.txt| awk '{print "cp" " "$NF,$NF}'| awk '{gsub("/","_",$NF);print $1,$2,"/root/p1/"\$3}'| sh


Here file /root/l.txt will be copied to /root/p1/ path but filename will be _root_l.txt Let me know for any confusion

Here /root/p1==> destination path