Quero renomear arquivos para alterar sua extensão, procurando efetivamente realizar
mv *.txt *.tsv
Mas ao fazer isso, recebo:
* .tsv não é um diretório
Acho um pouco estranho que os 10 primeiros hits do google mv
funcionem assim.
Quero renomear arquivos para alterar sua extensão, procurando efetivamente realizar
mv *.txt *.tsv
Mas ao fazer isso, recebo:
* .tsv não é um diretório
Acho um pouco estranho que os 10 primeiros hits do google mv
funcionem assim.
Respostas:
Quando você emite o comando:
mv *.txt *.tsv
o shell, vamos assumir o bash, expande os curingas se houver algum arquivo correspondente (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 será aprovada.
Novamente: o shell expande os padrões, não o programa.
Cargas de exemplos é talvez a melhor maneira, então vamos lá:
$ ls
file1.txt file2.txt
$ mv *.txt *.tsv
Agora, o que acontece na mv
linha é que o shell se expande *.txt
para os arquivos correspondentes. Como não há *.tsv
arquivos que não são alterados.
O mv
comando é 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, isso seria:
argc = 4
argv[0] = mv
argv[1] = file1.txt
argv[2] = file2.txt
argv[3] = *.tsv
O mv
programa verifica se o último argumento,, *.tsv
é um diretório. Como não é, o programa não pode continuar, pois não foi projetado para concatenar arquivos. (Normalmente, mova todos os arquivos para um.) Nem crie diretórios por capricho.
Como resultado, ele interrompe e relata o erro:
mv: target ‘*.tsv’ is not a directory
Agora, se você diz:
$ mv *1.txt *.tsv
O mv
comando é executado com:
argc = 3
argv[0] = mv
argv[1] = file1.txt
argv[2] = *.tsv
Agora, novamente, mv
verifique se *.tsv
existe. Como não, 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
Se você disse:
$ mkdir *.tsv
$ mv *.txt *.tsv
O mv
comando é 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 é realmente manter o curinga, deve-se sempre citá-lo. Ao citar, você evita que os curingas sejam expandidos se houver correspondências. Por exemplo, digamos mkdir "*.tsv"
.
A expansão pode ser vista ainda mais 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
Agora: o mv
comando pode e funciona em vários arquivos. Mas se houver mais de dois, o último terá que ser um diretório de destino. (Opcionalmente, você pode usar a -t TARGET_DIR
opção, pelo menos para GNU mv.)
Então, 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, poderá compartilhar. Assim como nas páginas de manual em que você afirma que isso é expresso.
Sei que isso não responde à sua pergunta, mas, se você estava procurando outra maneira de renomear os arquivos em comparação com o loop da solução alternativa, por que não usar find
? Eu usei esse comando várias vezes para substituir as extensões de arquivos em grandes diretórios por centenas de milhares de arquivos. Isso deve funcionar em qualquer sistema compatível com POSIX:
find . -name "*.gappedPeak" -exec sh -c 'mv "$1" "${1%.gappedPeak}.bed"' _ {} \;
Divisão de comando:
'
.
' => caminho de pesquisa começando no diretório atual marcado por '. "
-name
=> define o nome da correspondência de localização (nesse caso, todos os arquivos que terminam com.gappedPeak
)
-exec
=> execute o seguinte comando em cada partida
sh -c
=> 'exec' cria um ambiente de shell independente para cada correspondência
mv "$1" "${1%.gappedPeak}.bed"
=>mv
primeira variável (indicada por $ 1 ), que é o nome do arquivo atual, com o novo nome. Aqui eu faço uma correspondência de substring e apago; então pegue o primeiro var novamente, $ 1 e use%
para excluir.gappedPeak
da string. A.bed
no final apenas encadeia a variável remanescente, que é agora apenas , com , criando o novo nome de ficheiro.test#
.bed
test#.bed
O sublinhado é um espaço reservado por US $ 0
O
{}
é substituído por cada*.gappedPeak
nome de arquivo ( ) encontrado pelofind
comando e se torna $ 1 nosh
comando.
\;
marca o final do-exec
comando. Você também pode usar';'
ou";"
.
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
file.abc
-> blub.xyz
em vários sub dirs:find . -name "file.abc" -exec sh -c 'mv "$1" "$(dirname $1)/blub.xyz"' _ {} \;
mv *.txt *.tsv
não funciona; mv
pode renomear apenas um arquivo por vez. Você entendeu mal as explicações ou elas estão erradas.
mmv
e rename
pode renomear vários arquivos de uma vez. Mas existem duas versões em rename
torno das quais são chamadas de maneira diferente. Deve haver muitas perguntas sobre isso aqui.
rename
, não mv
.
mv *.txt *.tsv
mv
(geralmente) não vê *.txt
ou *.tsv
os nomes de arquivo expandidos pelo shell. O número de arquivos para os quais esses curingas se expandem seria "aleatório". A única situação em que isso funciona é se houver um arquivo com o nome *.txt
que será renomeado para (literalmente) *.tsv
(sem citar a bash
opção nullglob
não deve ser configurada).
foo.txt
e um chamado baz.tsv
a mv *.txt *.tsv
irá substituir o existente .tsv
arquivo ...
Por exemplo, se você tem asd.txt
e qwe.txt
arquivos no diretório ao executar o comando mv *.txt *.tsv
, ele tenta mover esses dois arquivos para um diretório chamado *.tsv
. Como não existe esse diretório, ocorre um erro.
rename(1)
rename
é um script perl de Larry Wall, o criador do perl. Ele usa um regex Perl e opera no nome do arquivo.
rename 's/\.txt$/.tsv/' *.txt
Se você precisar instalar rename
no Debian / Ubuntu, poderá fazer
sudo apt install rename
Outra opção a considerar é usar:
cp -p *.txt *.tsv
rm -f *.txt
*.txt
arquivos para *.tsv
preservar seus atributos usando o -p
sinalizador.*.txt
mv
que simplesmente altera o / directory / filename sem realmente mover os arquivos, a menos que estejam em uma partição diferente.