Rename multiple files with mv to change the extension

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

    You should explain **how** you want to rename those files exactly.

    Well i have files with an extension of *.gappedPeak and want to rename them to *.bed. they are all in the same directory it should be very simple but a full for loop was needed for me to succeed

    What you found on Google applies to MSDOS I think.

    @devnull 's alternate solution is really helpful

  • Runium

    Runium Correct answer

    6 years ago

    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.

    5 examples given without answering the question. How can this be the accepted answer?

License under CC-BY-SA with attribution

Content dated before 6/26/2020 9:53 AM