1

I have a Windows backup program that is creating a large number of sub-directories with a "$" at the end. The Linux client for that same backup program is expecting a ":" at the end of the directory name in order to restore the folders. Some folders have the "$" and others do not - to do with an internal versioning system.

If I am restoring a file from the windows client to another windows box, the backup program works great. The program is using "$" in windows because ":" is invalid in a path.

I am looking for a recursive rename in bash that will step through a path and find all of the folders with a single "$" char at the end and replace it with a ":"

My test data is this:

./a$
./b$
./c$
./white space$
./white space$/another test$
./white space$/another test$/a$
./white space$/another test$/b$
./white space$/another test$/x
./white space$/another test$/y
./white space$/test
./white space$/test 2
./white space$/testing$

I have tried :

find . -type d -name "*$" 

which gives me a list of the folders that need to be renamed

./a$
./b$
./c$
./white space$
./white space$/another test$
./white space$/another test$/a$
./white space$/another test$/b$
./white space$/testing$


find . -type d -name "*$" | sed 's/$$/\:/'   

gives me the end result I am looking for

./a:
./b:
./c:
./white space:
./white space$/another test:
./white space$/another test$/a:
./white space$/another test$/b:
./white space$/testing:

but I can't get it to rename in the same step. Also, I need it to work in reverse order (starting with the deepest match and working back) so that the first rename does not make the rest fail.

Bertrand Martel
  • 42,756
  • 16
  • 135
  • 159
jobber
  • 13
  • 2

1 Answers1

1

You can use this solution to take care of all spaces and special characters, then with printf '%d' you can get the depth for each matched directory, then perform a descending sort and build a rename command via awk to be executed with sh :

while IFS= read -r -d '' n; do
  printf '%q\n' "$n"
done < <(find . -type d -name "*$" -printf '%d|' -print0) | \
sort -r -k1 | \
awk -F '|' '{ printf "rename -v -n '\''s/\\$$/:/'\'' %s \n",$2 }' | \
sh

rename -n will only print names of file to be renamed, if you are ready, do the rename operation removing the -n :

while IFS= read -r -d '' n; do
  printf '%q\n' "$n"
done < <(find . -type d -name "*$" -printf '%d|' -print0) | \
sort -r -k1 | \
awk -F '|' '{ printf "rename -v '\''s/\\$$/:/'\'' %s \n",$2 }' | \
sh

Display progression

data=$(while IFS= read -r -d '' n; do
  printf '%q\n' "$n"
done < <(find . -type d -name "*$" -printf '%d|' -print0) | \
sort -r -k1);

count=$(echo "$data" | awk 'END{ print NR}');

echo "$data" | awk -F '|' -v count=$count '{ printf "echo -n \""NR"/"count" file : \";rename -v -n  '\''s/\\$$/:/'\'' %s \n",$2 }' | \
sh

Output :

1/8 file : ./white space$/another test$/b$ renamed as ./white space$/another test$/b:
2/8 file : ./white space$/another test$/a$ renamed as ./white space$/another test$/a:
3/8 file : ./white space$/testing$ renamed as ./white space$/testing:
4/8 file : ./white space$/another test$ renamed as ./white space$/another test:
5/8 file : ./white space$ renamed as ./white space:
6/8 file : ./c$ renamed as ./c:
7/8 file : ./b$ renamed as ./b:
8/8 file : ./a$ renamed as ./a:

Alternative

A more straightforward solution, use rnm bulk rename tool :

rnm -rs '/\$$/:/g' -dp -1 *
Community
  • 1
  • 1
Bertrand Martel
  • 42,756
  • 16
  • 135
  • 159
  • Glad to help, you can accept the answer if your problem is solved – Bertrand Martel Mar 08 '17 at 20:11
  • I ran it on my production data this morning, and it ran through and renamed about 90% of the folders on the first pass, but somewhere it must have renamed a base folder in the tree as about 300 folders could not be found. Running the script a second time resolved this. Wondering if there is a way to output the progress as it renames? – jobber Mar 11 '17 at 00:32
  • Did you run at first time with `-n` to see the list of directories impacted, were your missed folder enlisted ? I've added progression feature to my post – Bertrand Martel Mar 11 '17 at 00:57