Renomeie vários arquivos com mv para alterar a extensão

24

Eu quero renomear os arquivos para alterar sua extensão, efetivamente procurando realizar

mv *.txt *.tsv

Mas quando faço isso, obtenho:

*.tsv is not a directory

Acho estranho que os 10 primeiros hits do Google mostrem mv deva funcionar assim.

    
por Sander Van der Zeeuw 26.01.2015 / 16:03

6 respostas

20

Quando você emite o comando:

mv *.txt *.tsv

o shell, vamos assumir o bash, expande os curingas se houver arquivos correspondentes (incluindo diretórios). A lista de arquivos é passada para o programa, aqui mv . Se nenhuma correspondência for encontrada, a versão não expandida é passada.

Novamente: o shell expande os padrões, não o programa.

Muitos exemplos talvez sejam o melhor caminho, então aqui vamos nós:

Exemplo 1:

$ ls
file1.txt file2.txt

$ mv *.txt *.tsv

Agora, o que acontece na linha mv é que o shell expande *.txt para os arquivos correspondentes. Como não há arquivos *.tsv que não sejam alterados.

O comando mv é chamado com dois argumentos especiais :

  • argc : Número de argumentos, incluindo o programa.
  • argv : Uma matriz de argumentos, incluindo o programa como primeira entrada.

No exemplo acima, seria:

 argc = 4
 argv[0] = mv
 argv[1] = file1.txt
 argv[2] = file2.txt
 argv[3] = *.tsv

O programa mv verifica se o último argumento, *.tsv , é um diretório. Como não é, o programa não pode continuar, pois não é projetado para concatenar arquivos. (Normalmente, mova todos os arquivos em um.) Nem crie diretórios por capricho.

Como resultado, ele aborta e relata o erro:

mv: target ‘*.tsv’ is not a directory

Exemplo 2:

Agora, se você disser:

$ mv *1.txt *.tsv

O comando mv é executado com:

 argc = 3
 argv[0] = mv
 argv[1] = file1.txt
 argv[2] = *.tsv

Agora, novamente, mv verifique se *.tsv existe. Como isso não acontece, o arquivo file1.txt é movido para *.tsv . Ou seja: o arquivo é renomeado para *.tsv com o asterisco e tudo.

$ mv *1.txt *.tsv
‘file1.txt’ -> ‘*.tsv’

$ ls
file2.txt *.tsv

Exemplo 3:

Se você disser:

$ mkdir *.tsv
$ mv *.txt *.tsv

O comando mv é executado com:

 argc = 3
 argv[0] = mv
 argv[1] = file1.txt
 argv[1] = file2.txt
 argv[2] = *.tsv

Como *.tsv agora é um diretório, os arquivos acabam sendo movidos para lá.

Agora: usando comandos como some_command *.tsv quando a intenção é manter o caractere curinga, é sempre necessário citá-lo. Ao fazer citações, você evita que os curingas sejam expandidos, se houver alguma correspondência. Por exemplo. diga mkdir "*.tsv" .

Exemplo 4:

A expansão pode ainda ser visualizada se você fizer, por exemplo:

$ ls
file1.txt file2.txt

$ mkdir *.txt
mkdir: cannot create directory ‘file1.txt’: File exists
mkdir: cannot create directory ‘file2.txt’: File exists

Exemplo 5:

Agora: o comando mv pode e funciona em vários arquivos. Mas se houver mais de dois, o último deve ser um diretório de destino. (Opcionalmente você pode usar a opção -t TARGET_DIR , pelo menos para o GNU mv.)

Então está tudo bem:

$ ls -F
b1.tsv  b2.tsv  f1.txt  f2.txt  f3.txt  foo/

$ mv *.txt *.tsv foo

Aqui mv seria chamado com:

 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

e todos os arquivos acabam no diretório foo .

Quanto aos seus links. Você forneceu um (em um comentário), onde mv não é mencionado, mas rename . Se você tiver mais links, você pode compartilhar. Bem como para man pages onde você afirma que isso é expresso.

    
por 26.01.2015 / 17:30
27

Sei que isso não responde à sua pergunta, mas no caso de você estar procurando outra maneira de renomear os arquivos em comparação ao seu loop de trabalho, por que não usar find ? Eu usei este comando muitas vezes para substituir extensões de arquivo em diretórios grandes com centenas de milhares de arquivos nele. Isso deve funcionar em qualquer sistema compatível com POSIX:

find . -name "*.gappedPeak" -exec sh -c 'mv "$1" "${1%.gappedPeak}.bed"' _ {} \;

Falha no Comando:

  1. '.' => search path starting at current directory marked by ' . '

  2. -name => set find match name (in this case all files that end with .gappedPeak)

  3. -exec => execute the following command on every match

  4. sh -c => 'exec' creates an independent shell environment for each match

  5. mv "$1" "${1%.gappedPeak}.bed" => mv first 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 .gappedPeak from the string. The .bed at the end just concatenates the remaining variable, which is now just test#, with .bed, creating the new test#.bed filename.

  6. The underscore is a placeholder for $0

  7. The {} is replaced by each (*.gappedPeak) filename found by the find command, and becomes $1 to the sh command.

  8. \; marks the end of the -exec command.  You can also use ';' or ";".

Exemplo:

[user@before]# 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

[user@after]# 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
    
por 26.01.2015 / 17:54
8

mv *.txt *.tsv não funciona; mv pode renomear apenas um arquivo de cada vez. Você entendeu mal as explicações ou elas estão erradas.

mmv e rename podem renomear vários arquivos de uma só vez. Mas há duas versões de rename em torno das quais são chamadas de forma diferente. Deve haver muitas perguntas sobre isso aqui.

    
por 26.01.2015 / 16:08
4

Por exemplo, se você tiver asd.txt e qwe.txt arquivos no diretório quando executar o comando mv *.txt *.tsv , ele tentará mover esses dois arquivos para um diretório denominado *.tsv . Porque não existe tal diretório, dá um erro.

    
por 26.01.2015 / 16:11
2

rename(1)

rename é um script em perl de Larry Wall, o criador do perl. É preciso um regex Perl e opera no nome do arquivo.

rename 's/\.txt$/.tsv/' *.txt

Instalação

Debian / Ubuntu

Se você precisar instalar o rename no Debian / Ubuntu, você pode fazer

sudo apt install rename
    
por 29.04.2018 / 20:51
0

Outra opção a considerar é usar:

cp -p *.txt *.tsv
rm -f *.txt
  • A primeira linha copia todos os arquivos *.txt para *.tsv enquanto preserva seus atributos usando o sinalizador -p .
  • A segunda linha remove todos os arquivos com o padrão *.txt
  • Esse método exige que você tenha espaço em disco suficiente para manter temporariamente os arquivos de origem e de destino
  • Esse método é mais lento que mv , que simplesmente altera o / directory / filename sem realmente mover os arquivos, a menos que eles estejam em uma partição diferente.
por 29.04.2018 / 17:15

Tags