1

I want to rename all of the pdf files that contains spaces by replacing them by underscores. So I invoke the command:

ls *.pdf | sed -e 'p; s/" "/_/' | xargs -n2 mv

and I got errors on the terminal:

mv: cannot stat ‘Beginning’: No such file or directory
mv: cannot stat ‘Linux’: No such file or directory
mv: cannot stat ‘Line.pdf’: No such file or directory
mv: cannot stat ‘The’: No such file or directory
mv: cannot stat ‘Command’: No such file or directory
mv: cannot stat ‘Head’: No such file or directory
mv: cannot stat ‘C.pdf’: No such file or directory
mv: cannot stat ‘First’: No such file or directory
mv: cannot stat ‘Head’: No such file or directory
mv: cannot stat ‘PHP’: No such file or directory
mv: cannot stat ‘MySQL.pdf’: No such file or directory
mv: cannot stat ‘First’: No such file or directory
mv: cannot stat ‘and’: No such file or directory
mv: cannot stat ‘Linux’: No such file or directory
mv: cannot stat ‘Guide.pdf’: No such file or directory
mv: cannot stat ‘Pocket’: No such file or directory
mv: cannot stat ‘The’: No such file or directory
mv: cannot stat ‘C.pdf’: No such file or directory
mv: cannot stat ‘ANSI’: No such file or directory
mv: cannot stat ‘The’: No such file or directory
mv: cannot stat ‘Command’: No such file or directory
mv: cannot stat ‘The’: No such file or directory
mv: cannot stat ‘Command’: No such file or directory
mv: cannot stat ‘The’: No such file or directory
mv: cannot stat ‘Programming’: No such file or directory
mv: cannot stat ‘The’: No such file or directory
mv: cannot stat ‘Programming’: No such file or directory

So what is wrong in the command?

0

3 Answers 3

4

Get the Perl-based rename command (sometimes called prename) to do the job:

prename 's/ /_/g' *.pdf

The shell globbing keeps each file name separate; the prename command does bulk renaming; the s/ /_/g operation replaces each blank by _ everywhere in the file name. (The original code only replaces the first blank with an underscore, and then runs foul of xargs breaking on white space (blanks and tabs as well as newlines.)

1
  • very much my tool of the trade (also, lol @ duplicate :))
    – sehe
    Commented May 26, 2014 at 7:02
3

First of all, your sed command does not match any files because you are trying to match quote-space-quote instead of just a space. Unless you have a file literally named A" "file.pdf, you will not match it with sed.

Let's say you've fixed it to sed -e 'p; 's/ /_/g'. If you have a file called A file.pdf, your output will be

A file.pdf
A_file.pdf

and these you pass as arguments to xargs. However, xargs is instructed to take the first two arguments. In this case they will be A and file.pdf, neither of which exist, and therefore mv cannot stat them!

Here is, in my opinion, an easier way to do it:

for file in *.pdf; do mv "$file" "$(echo $file | sed 's/ /_/g')"; done
2
  • 1
    you can do without all the spurious sed processes
    – sehe
    Commented May 26, 2014 at 6:57
  • As @sehe points out, and as shown in the answer by @Noctua, you can forgo the use of sed by using Bash's own substitutions: mv "$file" "${file// /_}".
    – savanto
    Commented May 26, 2014 at 7:02
2

You could try quoting the filenames:

ls *.pdf | sed -e 's/.*/"&"/; p; s/ /_/g' | xargs -n2 mv

This is probably how you're doing it by hand, as well:

mv "File with spaces" "File_with_spaces"

Relying on pure bash, you'd have to use a for-loop and bash substitutions:

for file in $(ls *.pdf); do echo "$file" "${file// /_}"; done

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