Executando vários comandos em uma linha no shell

388

Digamos que eu tenho um arquivo /templates/applee quero

  1. colocá-lo em dois lugares diferentes e depois
  2. remova o original.

Então, /templates/appleserá copiado para /templates/usedAND /templates/inuse e depois disso eu gostaria de remover o original.

É cpa melhor maneira de fazer isso, seguida por rm? Ou há uma maneira melhor?

Eu quero fazer tudo em uma linha, então estou pensando que seria algo como:

cp /templates/apple /templates/used | cp /templates/apple /templates/inuse | rm /templates/apple

Essa é a sintaxe correta?

John Redyns
fonte

Respostas:

792

Você está usando |(canal) para direcionar a saída de um comando para outro comando. O que você está procurando é que o &&operador execute o próximo comando apenas se o anterior tiver êxito:

cp /templates/apple /templates/used && cp /templates/apple /templates/inuse && rm /templates/apple

Ou

cp /templates/apple /templates/used && mv /templates/apple /templates/inuse

Para resumir (não exaustivamente) os operadores / separadores de comando do bash:

  • |canaliza a saída padrão ( stdout) de um comando na entrada padrão de outro. Observe que stderrainda entra no destino padrão, seja lá o que for.
  • |&canaliza ambos stdoute stderrum comando na entrada padrão de outro. Muito útil, disponível na versão 4 e superior do bash.
  • &&executa o comando da direita &&apenas se o anterior tiver sido bem-sucedido.
  • ||executa o comando da direita ||apenas do que o anterior falhou.
  • ;executa o comando à direita de ;sempre, independentemente de o comando anterior ter êxito ou falha. A menos que set -etenha sido invocado anteriormente, o que causa bashfalha em um erro.
Maxim Egorushkin
fonte
6
Votado. Documentação oficial gnu.org/software/bash/manual/bash.html#Lists
flow2k
78

Por que não o cplocal 1 e depois o mvlocal 2. Isso cuida da "remoção" do original.

E não, não é a sintaxe correta. |é usado para "canalizar" a saída de um programa e transformá-la em entrada para o próximo programa. O que você quer é ;, que separa vários comandos.

cp file1 file2 ; cp file1 file3 ; rm file1

Se você precisar que os comandos individuais DEVEM ter sucesso antes que o próximo possa ser iniciado, use &&:

cp file1 file2 && cp file1 file3 && rm file1

Dessa forma, se um dos cpcomandos falhar, o rmnão será executado.

Marc B
fonte
10

Note que cp A B; rm Aé exatamente mv A B. Também será mais rápido, como você não precisa copiar os bytes (assumindo que o destino esteja no mesmo sistema de arquivos), apenas renomeie o arquivo. Então você quercp A B; mv A C

Glenn Jackman
fonte
7

Outra opção é digitar Ctrl+V Ctrl+Jno final de cada comando.

Exemplo (substitua #por Ctrl+V Ctrl+J):

$ echo 1#
echo 2#
echo 3

Resultado:

1
2
3

Isso executará os comandos, independentemente se os anteriores falharam.

Igual a: echo 1; echo 2; echo 3

Se você deseja interromper a execução em comandos com falha, adicione &&no final de cada linha, exceto a última.

Exemplo (substitua #por Ctrl+V Ctrl+J):

$ echo 1 &&#
failed-command &&#
echo 2

Resultado:

1
failed-command: command not found

Em zshvocê também pode usar Alt+Enterou em Esc+Entervez deCtrl+V Ctrl+J

Eyal Levin
fonte
3

Tente isso ..

cp /templates/apple /templates/used && cp /templates/apple /templates/inuse && rm /templates/apple

Pedro
fonte
2

Usar cachimbos me parece estranho. De qualquer forma, você deve usar o andoperador lógico Bash:

$ cp /templates/apple /templates/used && cp /templates/apple /templates/inuse && rm /templates/apples

Se os cpcomandos falharem, o rmnão será executado.

Ou, você pode criar uma linha de comando mais elaborada usando um forloop e cmp.

Renaud
fonte