Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bash error renaming files with spaces - mv target is not a directory

I'm trying to rename a bunch of files which contain spaces in them, getting rid of the spaces. I thought I found the correct bash command:

for f in *.txt; do mv \"$f\" ${f/ /}; done

However, this gives the error, "mv: target is not a directory" for each file. If I replace 'mv' with 'echo mv' in the command, it prints the proper mv command for each file, and if I type any of those mv commands individually, they work. For example, if I have 2 files, "a .txt", and "b .txt", and run the command above, I get:

mv: target 'a.txt' is not a directory
mv: target 'b.txt' is not a directory

If I type the command:

for f in *.txt; do echo mv \"$f\" ${f/ /}; done

I get:

mv "a .txt" a.txt
mv "b .txt" b.txt

I've found another way to do this, using "rename", but I would like to know why this doesn't work.

like image 654
Jim Hines Avatar asked Oct 23 '14 00:10

Jim Hines


People also ask

Is not a directory mv command?

When you specify a single source file and the target is not a directory, mv moves the source to the new name, by a simple rename if possible. If a destination file exists and you do not have write permission for it, mv prompts with the name of the existing file.

How do I rename a file in bash?

You can also rename a file by using a command in bash script. Many commands exist in Linux to rename a filename. The command 'mv' is the most popular command for renaming a file. There is another command called 'rename' that can also be used for the same task.

What is the Move command in Linux?

mv stands for move. mv is used to move one or more files or directories from one place to another in a file system like UNIX.


2 Answers

Try:

for f in *.txt; do mv "$f" "${f// /}"; done 

Three points:

  1. The quotes around a shell variable should not be escaped.

  2. In general, it is a good idea to put double-quotes around every reference to a shell variable.

  3. ${f/ /} removes just the first occurrence of a space. To remove all spaces, use ${f// /}.

What went wrong

$ touch {a,b}" .txt" $ ls *.txt a .txt  b .txt $ for f in *.txt; do mv \"$f\" ${f/ /}; done mv: target `a.txt' is not a directory mv: target `b.txt' is not a directory 

The expression \"$f\" does not behave like it is double quoted. It expands to two arguments, such as "a and .txt", where the double-quotes are treated as normal characters, just like the a is a normal character. Because there are three arguments to mv ("a and .txt" and a.txt), mv believes that you are trying to move the first two arguments to the third and the third is required to be a directory. Since the third is not a directory, it issues an error message.

like image 91
John1024 Avatar answered Sep 28 '22 15:09

John1024


Because this is the first thing that came up on google when googling this error, I thought I'd add a bit.

This error occurs if you have more than two arguments and the last result is not a directory.

This works (when output.txt does not exist):

mv file1.txt output.txt

This does not (if file2.txt does exist):

mv file1.txt file2.txt

In my case I was doing: mv prefix_* output_file_name to ensure a downloaded file had a consistant name, but another file had appeared in the directory, restulting in the "mv target is not a directory" error

like image 21
sdfgeoff Avatar answered Sep 28 '22 15:09

sdfgeoff