I have a folder structure like this:


It should be like this:


I can find the folders I need to move or rename using

find . -path "*/files/a" -type d

But how do I rename the results?

  • 1
    Is the leading directory always one level deep, or do you need the find because there's, for example, /ms/other/directory/files/a? – Jeff Schaller Feb 27 at 16:29
  • It's always one level deep – Lennart Feb 27 at 16:34
  • Found it: should use the full path and * as wildcard. Thanx for your help @JeffSchaller! – Lennart Feb 27 at 16:46

One way:

for d in /*/files/a/
  mv "$d" "${d%a/}b"

... which uses * to match all of the initial "client" top-level directories, followed by the required /files/a/ subdirectory structure. It then uses parameter expansion to strip the trailing a/ off of each one and then "replace" it with a b for the rename.

  • Thanks! But... I get an error: mv: cannot stat `?/files/a/': No such file or directory. When I use a hardcoded path it works, problem seems with the ? – Lennart Feb 27 at 16:25
  • I used the "/client" portion from your question, where I assumed that each "client" directory had a single digit after it. Are those your actual directory names? – Jeff Schaller Feb 27 at 16:26
  • Also: the /client1/ part is the name of a client (e.g. /microsoft/files/a, /google/files/a, etc). – Lennart Feb 27 at 16:26
  • Then I was inadvertently distracted by the similar pattern. Could you edit the question to describe the commonalities & differences in the files /directories you want to match? Thanks! – Jeff Schaller Feb 27 at 16:28
  • @Lennart, I've reworked the answer given the actual directory structure. – Jeff Schaller Feb 27 at 16:45

A hacky solution:

eval $(find . -path "*/files/a" -type d -print | xargs -n1 -exec echo | sed 's/\(.*\/\)\(.*\)$/mv \1\2 \1b;/')

Sed creates the arguments for the mv command. The output is then eval'ed.

If we remove eval $(), it looks like this executed on three test folders in the path:

$ find . -path "*/files/a" -type d -print | xargs -n1 -exec echo | sed 's/\(.*\/\)\(.*\)$/mv \1\2 \1b;/'
mv ./client1/files/a ./client1/files/b;
mv ./client2/files/a ./client2/files/b;
mv ./client3/files/a ./client3/files/b;

Done by below method and it worked fine

for i in /ms/files/  /fb/files/ /db/files/; do find $i -type d; done| sed -n '/a$/p'| awk '{print "sudo mv" " " $1 " " substr($1,1,10)"b/"}'|sh

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.