Como evitar que o 'mv' mova uma coleção de arquivos para um único regular?

16

Acabei de perder uma pequena parte da minha coleção de áudio, por um erro estúpido que cometi. :-(
Felizmente eu tinha um backup bastante recente, mas ainda era irritante. Além de você, o outro culpado que fez o dano foi mv , que mostrará o seguinte:

Os arquivos de áudio tinham um certo esquema:

ARTIST - Some Title YY.mp3

em que YY é a especificação de ano com dois dígitos.

mkdir 90<invisible control character>

(Até o momento, eu não sabia que eu tinha realmente 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 a ideia do que aconteceu eh? : - >
O resultado (desastroso) era um diretório virgem empty chamado '90 algo '(com algo sendo o caractere de controle "invisível") e um único arquivo chamado '90', sobrescrito n vezes.

TODOS OS ARQUIVOS FORAM IDENTIFICADOS. : - (((obviamente)

Desejo mv ter verificado no tempo se a assinatura do "arquivo" de destino (lembre-se em * NIX: Tudo é um arquivo ) começa com d------ (ex. drwxr-xr-x ). E, claro, se o destino existe em tudo. Há uma variante do cenário acima, quando você simplesmente esqueceu para mkdir do diretório primeiro. (mas claro, você assumiu que está lá ...)

Até mesmo nosso sistema operacional que odeia animais de estimação começando com o W FAZEM ISSO. Você começa mesmo solicitado para especificar o tipo de destino (arquivo? Diretório?) Se você pedir por ele.

Por isso, estou pensando se nós * NIXers ainda temos que nos escrever um " mv scriptlet" apenas para evitar esses tipos de surpresas indesejadas.

    
por syntaxerror 21.11.2014 / 09:13

6 respostas

37

Você pode acrescentar / ao destino se quiser mover arquivos para um diretório. Caso o diretório não exista, você receberá um erro:

mv somefile somedir/
mv: cannot move ‘somefile’ to ‘somedir/’: Not a directory

No caso do diretório existir, ele move o arquivo para esse diretório.

    
por 21.11.2014 / 09:34
20

O GNU coreutils 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 irá reclamar em vez de mover todos os seus arquivos para o mesmo nome de arquivo.

Eu teria escrito seu proponente da seguinte forma:

find . -name '* 9?.mp3' -exec mv -t 90 {} +

Observe o uso de + em vez de \; , agrupando tantos nomes de arquivos quanto possível, resultando em uma execução mais rápida.

    
por 21.11.2014 / 09:33
10

Além disso, se você geralmente planeja evitar sobregravações acidentais no futuro, há a opção -i para mv . Eu pessoalmente não consigo pensar em nenhuma desvantagem se você

alias mv='mv -i'

Se você precisar substituir algo, simplesmente passe a opção -f .

Os alias só terão efeito se você digitar o comando diretamente em um shell interativo, não para casos como invocação de find . Você poderia ter corrido

find . -name '* 9?.mp3' -exec mv -i {} 90 \;

e, em seguida, você teria sido solicitado se mv tivesse tentado substituir um arquivo existente.

    
por 21.11.2014 / 16:07
7

Além das excelentes respostas acima, gostaria de esclarecer por que você não recebeu a pergunta sobre mover os arquivos ou não.

Se você mover um arquivo para um novo nome, e esse nome não for um diretório, mv irá renomear seu arquivo para o novo nome.

O problema aqui é que você estava usando find para executar mv uma vez por arquivo , não uma vez para todos os arquivos .

Se, em vez disso, você tivesse feito mv *90.mp3 90 , então mv teria falhado com a mensagem de erro "o arquivo de destino não é um diretório".

Outro conselho é usar a conclusão de tabulação ao digitar o caminho de destino. Ele mostrará se o destino é um diretório adicionando / ao nome de destino. Você também pode usar mv -i para saber se deseja substituir um arquivo existente.

    
por 21.11.2014 / 10:05
1

Como uma estratégia alternativa de propósito geral, gostaria de sugerir transformar esse tipo de operação em um script temporário. Eu prefiro ver os resultados de find e transformá-los em um comando mv com a mão, garantindo que eu entenda o que estou fazendo antes de executar. por exemplo.

find . -name '* 9?.mp3' > tmp
vim tmp

Agora eu posso olhar através de uma lista de nomes de arquivos e reescrever o conteúdo do arquivo como um comando shell.

  • Coloque o conteúdo do arquivo em uma linha: ggVGJ
  • Prepend: Imv [esc]
  • Anexar: Asomedir/ [esc]
  • Salve o arquivo. Leia isso novamente. Respire.
  • Execute source tmp na linha de comando.

É uma estratégia conservadora, mas eu fui mordido com muita frequência por comandos -exec ou sed errados ou entendi mal as expansões de shell, e prefiro uma abordagem lenta e consistente.

Em outras palavras: sou covarde demais para usar -exec .

    
por 21.11.2014 / 17:59
0

Outra opção:

-n, --no-clobber do not overwrite an existing file

é o mesmo que -i, mas não vai perguntar, vai falhar.

    
por 27.11.2014 / 22:04

Tags