I want to rename files to change their extension, effectively looking to accomplish
mv *.txt *.tsv
But when doing this I get :
*.tsv is not a directory
I find it somewhat strange that the first 10 google hits show mv should work like this.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
I know this doesn’t answer your question, but in case you were looking for another way to rename the files compared to your work-around loop, why not use find? I have used this command many times to replace file extensions in large directories with hundreds of thousands of files in it. This should work on any POSIX-compliant system:
find . -name "*.gappedPeak" -exec sh -c 'mv "$1" "${1%.gappedPeak}.bed"' _ {} ;
Command Breakdown:
- ‘
.‘ => search path starting at current directory marked by ‘ . ‘-name=> set find match name (in this case all files that end with
.gappedPeak)-exec=> execute the following command on every matchsh -c=> ‘exec’ creates an independent shell environment for each matchmv "$1" "${1%.gappedPeak}.bed"=>mvfirst variable (denoted by $1),
which is the current file name, to new name. Here I do a substring match and delete; so take first var again, $1 and use%to delete.gappedPeakfrom the string. The.bedat the end just concatenates the remaining variable, which in the example below would now betestNumber, with.bed, creating the newtestNumber.bedfilename.- The underscore is a placeholder for $0
- The
{}is replaced by each (*.gappedPeak) filename found
by thefindcommand, and becomes $1 to theshcommand.;marks the end of the-execcommand.
You can also use';'or";".
Example:
[<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fe8b8d9b8cbe9c9b98918c9b">[email protected]</a>]# ls -lh total 0 -rw-r--r--. 1 root root 0 Jan 26 11:40 test1.gappedPeak -rw-r--r--. 1 root root 0 Jan 26 11:40 test2.gappedPeak -rw-r--r--. 1 root root 0 Jan 26 11:40 test3.gappedPeak -rw-r--r--. 1 root root 0 Jan 26 11:40 test4.gappedPeak -rw-r--r--. 1 root root 0 Jan 26 11:40 test5.gappedPeak [<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="087d7b6d7a48696e7c6d7a">[email protected]</a>]# ls -lh total 0 -rw-r--r--. 1 root root 0 Jan 26 11:40 test1.bed -rw-r--r--. 1 root root 0 Jan 26 11:40 test2.bed -rw-r--r--. 1 root root 0 Jan 26 11:40 test3.bed -rw-r--r--. 1 root root 0 Jan 26 11:40 test4.bed -rw-r--r--. 1 root root 0 Jan 26 11:40 test5.bed
Method 2
When you issue the command:
mv *.txt *.tsv
the shell, lets assume bash, expands the wildcards if there are any matching files (including directories). The list of files are passed to the program, here mv. If no matches are found the unexpanded version is passed.
Again: the shell expands the patterns, not the program.
Loads of examples is perhaps best way, so here we go:
Example 1:
$ ls file1.txt file2.txt $ mv *.txt *.tsv
Now what happens on the mv line is that the shell expands *.txt to the matching files. As there are no *.tsv files that is not changed.
The mv command is called with two special arguments:
argc: Number of arguments, including the program.argv: An array of arguments, including the program as first entry.
In the above example that would be:
argc = 4 argv[0] = mv argv[1] = file1.txt argv[2] = file2.txt argv[3] = *.tsv
The mv program check to see if last argument, *.tsv, is a directory. As it is not, the program can not continue as it is not designed to concatenate files. (Typically move all the files into one.) Nor create directories on a whim.
As a result it aborts and reports the error:
mv: target ‘*.tsv’ is not a directory
Example 2:
Now if you instead say:
$ mv *1.txt *.tsv
The mv command is executed with:
argc = 3 argv[0] = mv argv[1] = file1.txt argv[2] = *.tsv
Now, again, mv check to see if *.tsv exists. As it does not the file file1.txt is moved to *.tsv. That is: the file is renamed to *.tsv with the asterisk and all.
$ mv *1.txt *.tsv ‘file1.txt’ -> ‘*.tsv’ $ ls file2.txt *.tsv
Example 3:
If you instead said:
$ mkdir *.tsv $ mv *.txt *.tsv
The mv command is executed with:
argc = 3 argv[0] = mv argv[1] = file1.txt argv[1] = file2.txt argv[2] = *.tsv
As *.tsv now is a directory, the files ends up being moved there.
Now: using commands like some_command *.tsv when the intention is to actually keep the wildcard one should always quote it. By quoting you prevent the wildcards from being expanded if there should be any matches. E.g. say mkdir "*.tsv".
Example 4:
The expansion can further be viewed if you do for example:
$ ls file1.txt file2.txt $ mkdir *.txt mkdir: cannot create directory ‘file1.txt’: File exists mkdir: cannot create directory ‘file2.txt’: File exists
Example 5:
Now: the mv command can and do work on multiple files. But if there is more then two the last has to be a target directory. (Optionally you can use the -t TARGET_DIR option, at least for GNU mv.)
So this is OK:
$ ls -F b1.tsv b2.tsv f1.txt f2.txt f3.txt foo/ $ mv *.txt *.tsv foo
Here mv would be called with:
argc = 7 argv[0] = mv argv[1] = b1.tsv argv[2] = b2.tsv argv[3] = f1.txt argv[4] = f2.txt argv[5] = f3.txt argv[6] = foo
and all the files end up in the directory foo.
As for your links. You have provided one (in a comment), where mv is not mentioned at all, but rename. If you have more links you could share. As well as for man pages where you claim this is expressed.
Method 3
mv *.txt *.tsv doesn’t work; mv can rename only one file at a time. You have either misunderstood the explanations or they are wrong.
mmv and rename can rename several files at once. But there are two versions of rename around which are called differently. There should be plenty of questions about that here.
Method 4
rename(1)
rename is a perl script by Larry Wall the maker of perl. It takes a Perl regex and operates on the file name.
rename 's/.txt$/.tsv/' *.txt
Installation
Debian/Ubuntu
If you need to install rename on Debian/Ubuntu you can do
sudo apt install rename
Method 5
For example, if you have asd.txt and qwe.txt files in the directory when you run the command mv *.txt *.tsv, it tries to move these two files into a directory named *.tsv. Because there is no such directory, it gives an error.
Method 6
Apparently the easiest way under Linux OS is :
- Click on file
- Press F2 (rename)
- alter the file name as you like
- press <ENTER>
I guess sometimes DOS does win. 🙂
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0
