3

I have a directory which contains files and sub directories, some of which have whitespace in their names. Further more each of these sub directories contains files with whitespace in their names. Is there a simple way to remove the whitespace from all the names in the parent directory and all sub directories at once?

1

Is there a simple way to remove the whitespace from all the names in the parent directory and all sub directories at once?

Yes there is:

find /tmp/ -depth -name "* *" -execdir rename 's/ /_/g' "{}" \;

Further Reading

Good Luck!

3

Use the find command to enumerate the files you need to rename. Select only file names with spaces for performance. Pass the -depth option to act on files in subdirectories before acting on the directory itself, since renaming the directories as find is traversing them will result in some directories being missed.

find /path/to/directory -depth -name '* *' -exec … {} +

If you have the prename command, it applies a Perl expression to rename files. You need to take care to act only on the file's base name, not on the whole directory path. If your find has the -execdir action, that's a convenient way of doing this:

find /path/to/directory -name '* *' -execdir prename 's/ //g' {} +

Replace s/ //g by s/ /_/g to replaces spaces by underscores rather than remove them outright, or s/ +/_/g to replace sequences of spaces by a single underscore.

Without -execdir you need the directory avoidance logic in the Perl code.

find /path/to/directory -depth -name '* *' -exec prename '
    s:.*/::; $dir=$&;
    s/ //g;
    $_="$dir$_"
' {} +

If you don't have prename, you can do this with a shell script. You'll need to invoke a shell from find. If you have ksh, you can use its ${file// /} construct to get the value of the variable file with spaces removed (use ${file// /_} to replace each space by an underscore):

find /path/to/directory -depth -name '* *' -execdir ksh -c '
    mv "$0" "${0// /}"
' {} \;

or

find /path/to/directory -depth -name '* *' -exec ksh -c '
    for file do
      dir=${file%/*};
      file=${x##*/};
      mv "$dir/$file" "$dir/${file// /}";
    done
' _ {} +

If you have bash or mksh, you can use it instead of ksh. If you have none, you can use sed to do the string processing.

find /path/to/directory -depth -name '* *' -exec sh -c '
    for file do
      dir=${file%/*};
      file=${x##*/};
      without_spaces=$(printf %s "$file." | sed "s/ //g")
      mv "$dir/$file" "$dir/${without_spaces%.}";
    done
' _ {} +

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.