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 '19 at 16:29
  • It's always one level deep
    – Lennart
    Feb 27 '19 at 16:34
  • Found it: should use the full path and * as wildcard. Thanx for your help @JeffSchaller!
    – Lennart
    Feb 27 '19 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 '19 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 '19 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 '19 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 '19 at 16:28
  • @Lennart, I've reworked the answer given the actual directory structure.
    – Jeff Schaller
    Feb 27 '19 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.