Acabei de perder uma pequena parte da minha coleção de áudio, por um erro estúpido que cometi. :-(
Felizmente, eu tinha um backup relativamente recente, mas ainda era irritante. Além do seu, o outro culpado foi o que causou a travessura mv
, que mostrará o seguinte:
Os arquivos de áudio tinham um certo esquema:
ARTIST - Some Title YY.mp3
onde YY
é a especificação do ano com 2 dígitos.
mkdir 90<invisible control character>
(Até o momento, eu não sabia que havia digitado um terceiro caractere em excesso que era invisível ...!)
Em vez de ter tudo em um diretório, eu queria ter todas as músicas dos anos 90 em um diretório. Então eu digitei:
find . -name '* 9?.mp3' -exec mv {} 90 \;
Não é tão difícil entender o que aconteceu, não é? : ->
O resultado (desastroso) foi um diretório vazio virgem chamado '90 something '(com algo sendo o caractere de controle "invisível") e um único arquivo chamado' 90 ', sobrescrito n vezes.
Todos os arquivos foram embora. :-(( (obviamente)
Desejo mv
teria verificado no tempo se a assinatura do "arquivo" de destino (lembre-se em * NIX: Tudo é um arquivo ) começa com um d------
(por exemplo drwxr-xr-x
). E, é claro, se o destino existe . Existe uma variante do cenário acima mencionado, quando você simplesmente esqueceu-se para mkdir
o diretório em primeiro lugar. (mas é claro, você assumiu que está lá ...)
Mesmo o nosso OS pet-ódio começando com a capital W faz isso. Você é solicitado a especificar o tipo de destino (arquivo? Diretório?), Se solicitar.
Por isso, estou me perguntando se nós * NIXers ainda temos que escrever um " mv
scriptlet" para evitar esse tipo de surpresa indesejável.
.mp3
deve estar lá com o nome90
, poderia ter sido aquele para o qual você não tinha um backup.mv
não é o problema aqui, tecnicamente, ele não sabe que você está movendo uma série de arquivos. Você está executandomv
uma vez para cada arquivo. É assim quefind -exec ;
funciona. Se você tivesse usadofind -exec +
(como em alguns dos comentários)mv
teria gritado assim que recebesse mais de um argumento.mv
de cada arquivo possa parecer um pouco menos pensada a princípio, ela (como eu havia dito anteriormente) será a única solução sã quando os arquivos de origem estiverem espalhados entre vários subdiretórios. Que no meu caso de teste, os arquivos de origem estavam todos em um diretório, não significa que esse seja o meu caso de teste real . Na verdade, é apenas uma simplificação, porque eu posso elaborar isso sozinho depois. Além disso, torna as perguntas menos demoradas para ler devido ao tamanho reduzido. :)mv
exigir que o destino exista?mv oldfile newfile
é a maneira de renomear um arquivo, e é bobagem esperarnewfile
já existir e ser um diretório.Respostas:
Você pode anexar
/
a ao destino se desejar mover arquivos para um diretório. Caso o diretório não exista, você receberá um erro:Caso o diretório exista, ele move o arquivo para esse diretório.
fonte
O coreutils GNU
mv
já tem uma opção especificando que você deseja mover para um diretório:-t
/--target-directory
. Se o argumento para essa opção não existir,mv
ele reclamará em vez de mover todos os seus arquivos para o mesmo nome de arquivo.Eu teria escrito o seu motor da seguinte maneira:
Observe o uso de em
+
vez de\;
agrupar o máximo de nomes de arquivos possível, resultando em uma execução mais rápida.fonte
find . -name '* 9?.mp3' -exec sh -c 'exec mv "$@" 90/' sh {} +
Além disso, se você geralmente planeja evitar substituições acidentais no futuro, existe a
-i
opçãomv
. Eu pessoalmente não consigo pensar em nenhuma desvantagem se vocêSe você precisar sobrescrever algo, simplesmente passe a
-f
opção.Os aliases só entram em vigor se você digitar o comando diretamente em um shell interativo, não para casos como invocação por
find
. Você poderia ter corridoe você seria solicitado se
mv
tentasse sobrescrever um arquivo existente.fonte
mv
. Esse "truque" menos conhecido fará com que o comando com a barra invertida anexada a ele ignore quaisquer definições de alias.find ... -exec mv ...
, precisará criar~/bin/mv
(ou algum outro diretório apropriado) e fazê-lo/bin/mv -i "$@"
- porquefind ... -exec
não procura aliases.env mv
. Menos digitação. :) Como meu layout de teclado local exige que a tecla SHIFT seja pressionada para uma barra, sempre eu preferiria versões "sem barra" (se aplicável).mv
um local no início de$PATH
seria uma solução mais limpa. Por outro lado, eumv
descuidadamente no shell interativo (porque isso acontece rápido). No momento em que componho algo mais complexo, comofind
umfor
loop ou mesmo um script de shell, costumo executar algumas execuções a seco (usandoecho
) para garantir que não quebre algo. Nesses casos, não preciso de mãos dadasmv
, porque já estou pensando nisso.Além das excelentes respostas acima, gostaria de esclarecer por que você não recebeu a pergunta sobre mover ou não os arquivos.
Se você mover um arquivo para um novo nome, e esse nome não for um diretório,
mv
renomeará seu arquivo para o novo nome.O problema aqui é que você estava usando
find
para executarmv
uma vez por arquivo , não uma vez para todos os arquivos .Se, em vez disso, você tiver feito
mv *90.mp3 90
,mv
teria falhado com a mensagem de erro "O arquivo de destino não é um diretório".Outro conselho é usar o preenchimento de guias ao digitar o caminho de destino. Ele mostrará se o destino é um diretório adicionando
/
ao nome do destino. Você também podemv -i
ser perguntado se deseja substituir um arquivo existente.fonte
mv *90.mp3 90
, o mv teria falhado com a mensagem de erro "O arquivo de destino não é um diretório". Hah, sim, por que tão complicado, eh? Eu uso sua linha e serei feliz. Apenas neste caso trivial, no entanto. :) Como essa é a maneira normal de fazer minhas perguntas: eu as reduzirei por uma questão de simplicidade. Ninguém se opôsfind
até agora, considerando que os arquivos dos anos 90 também poderiam estar espalhados em vários subdiretórios que eu também quero "capturar". Se e somente se eles estiverem sempre em um diretório de origem, suamv
linha será aplicável.mv
se comporta, não como uma crítica à sua escolha de ferramentas.find
emv
, por exemplofind /music -type d -exec mv {}/*90.mp3 targetdir\;
-, mas agora eu me sinto um pouco como eu estou complicar-lo, e simplesmente usando-i
ou-t
é mais eficientefind . -type d -exec mv {}/*9?.mp3 target \;
exemplo funcionasse, ainda haveria o risco de omv
comando parecermv file target
para cada diretório que continha apenas um*9?.mp3
arquivo; então todos esses arquivos (exceto o último) seriam perdidos.*.mp3
arquivos em uma árvore de diretórios, você poderáshopt -s globstar
executar o seu comando**/*.mp3
-**
ele funcionará como afind
.Como estratégia alternativa de uso geral, eu gostaria de sugerir transformar esse tipo de operação em um script temporário. Prefiro examinar os resultados
find
e transformá-los em ummv
comando manualmente, garantindo que eu entenda o que estou fazendo antes de executar. por exemplo.Agora eu posso olhar através de uma lista de nomes de arquivos e reescrever o conteúdo do arquivo como um comando shell.
ggVGJ
Imv
[esc]
Asomedir/
[esc]
source tmp
na linha de comando.É uma estratégia conservadora, mas muitas vezes fui mordido por comandos
-exec
ou erros de digitação oused
expansões de shell mal compreendidas, e prefiro adotar uma abordagem lenta e consistente.Em outras palavras: sou covarde demais para usar
-exec
.fonte
:%s/.*/"&"/
etapa - porque, nesse caso, você sabe que todo nome de arquivo contém pelo menos um espaço.echo mv
vez demv
e remover oecho
se você estiver feliz.Outra opção:
é o mesmo que -i, mas não pergunta, vai falhar.
fonte