I have a large directory with hundreds of folders, all following the naming scheme "a_b_x", with x being a random word. In every one of these folders there are 3 text files, all with a couple of strings containing "a_b_x" as well.

I'm trying to rename all of the directories and change the strings inside the files from "a_b_x" to "a_x", meaning the "b_" is supposed to be removed. I hope to accomplish this with some sed wizardry, as manually editing all of the files would take several hours.


You can use this command :

for folder in $(ls); do
    for file in $(ls $folder); do
        sed -i 's/_b//' $folder/$file
    mv $folder ${folder/_b/}
  • First loop is browsing directories.
  • Second loop is editing contents of files located in folders.

    After leaving second loop, first one is renaming folders.

Another way for dealing with spaces in filenames which would be interpreted as IFS :

ls | while read folder ; do
 ls "$folder" | while read file; do
  sed -i 's/_b//' "$folder/$file"
 mv "$folder" "${folder/_b/}"

You should always avoid parsing the output of ls. Try this (thanks to stephane-chazelas for suggesting ./*/):

for folder in ./*/; do     
      sed -i 's/_b//g' "$f"/*; mv "$folder" "${folder/_b/}"; 
  • Parsing the output of find has the same issues as parsing the output of ls. Use -exec with find, or just loop over */: for folder in ./*/ – Stéphane Chazelas Feb 19 '13 at 14:16
  • @StephaneChazelas find does not have these problems when used in combination with IFS= and -print0 (which I forgot in my original answer. – terdon Feb 19 '13 at 16:14
  • For -print0, you need read -d '' for which you need zsh or bash. Note the for folder in ./*/ which I mentioned earlier would include symlinks to directories (whether it's desirable or not) – Stéphane Chazelas Feb 19 '13 at 17:26
  • @StephaneChazelas Ah, yes, I am a bash person, true. Why do you need -d for bash? It seems to work fine as is. – terdon Feb 19 '13 at 19:37

Here you are

root@testbox:~# mkdir test
root@testbox:~# cd test
root@testbox:~/test# mkdir -p a_b_x{1..10} # populate directories
root@testbox:~/test# printf 'a_b_x\na_b_y\nfoo\nbar\n' | \
    tee a_b_x{1..10}/somefile # populate files

Rename directories:

root@testbox:~/test# find . -name a_b_\* -type d -print0 | \
    xargs -r0 rename -v 's/a_b_/a_/'
./a_b_x10 renamed as ./a_x10
./a_b_x5 renamed as ./a_x5
./a_b_x7 renamed as ./a_x7
./a_b_x4 renamed as ./a_x4
./a_b_x8 renamed as ./a_x8
./a_b_x3 renamed as ./a_x3
./a_b_x9 renamed as ./a_x9
./a_b_x6 renamed as ./a_x6
./a_b_x1 renamed as ./a_x1
./a_b_x2 renamed as ./a_x2

Edit files:

root@testbox:~/test# find . ! -name \*.bak -type f -print0 | xargs -r0 sed -i.bak 's,a_b_,a_,'
root@testbox:~/test# cat a_x4/somefile

Remove backups if all ok:

root@vm8583:~/test# find . -name \*.bak -type f -delete
  • Nice, thank you for rename, in Perl no less! Is it part of the default Perl installation? – terdon Feb 19 '13 at 22:08
  • This rename (prename) is from default perl installaton on Debian, the same can be achieved with rename (rename.ul) from util-linux package with slightly different call syntax: rename.ul -v a_b_ a_ .... – artyom Feb 20 '13 at 3:55

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.