Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'm facing an issue I'm not quite sure how to overcome. 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.

I'd be very thankful for any help!

share|improve this question
up vote -1 down vote accepted

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/}"
share|improve this answer
Never use for loops with ls, use while and quote the variables to deal with spaces. – terdon Feb 19 '13 at 11:35
This seems to work, thanks! – naosia Feb 19 '13 at 12:08

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/}"; 
share|improve this answer
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
share|improve this answer
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 posting your answer, you agree to the privacy policy and terms of service.

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