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?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
segfault
  • 70
  • 1
  • 6

3 Answers3

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.)

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
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
savanto
  • 4,470
  • 23
  • 40
  • 1
    you can do without all the spurious `sed` processes – sehe May 26 '14 at 06:57
  • As @sehe points out, and as shown in [the answer by @Noctua](http://stackoverflow.com/a/23864321/3565972), you can forgo the use of `sed` by using Bash's own substitutions: `mv "$file" "${file// /_}"`. – savanto May 26 '14 at 07: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
Noctua
  • 5,058
  • 1
  • 18
  • 23