
Costumo ver tutoriais online que conectam vários comandos com símbolos diferentes. Por exemplo:
command1 | command2
command1 & command2
command1 || command2
command1 && command2
Outros parecem estar conectando comandos a arquivos:
command1 > file1
command1 >> file1
O que são essas coisas? O que eles chamaram? O que eles fazem? Existem mais deles?
Responder1
Eles são chamados de operadores shell e sim, existem mais deles. Darei uma breve visão geral dos mais comuns entre as duas classes principais,operadores de controleeoperadores de redirecionamentoe como eles funcionam em relação ao shell bash.
A. Operadores de controle
Na linguagem de comando shell, um token que executa uma função de controle.
É um dos seguintes símbolos:
& && ( ) ; ;; <newline> | ||
E |&
na festa.
Um !
énãoum operador de controle, mas umPalavra reservada. Torna-se um NOT lógico [operador de negação] dentroExpressões Aritméticase dentro de construções de teste (embora ainda exija um delimitador de espaço).
A.1 Lista de terminadores
;
: executará um comando após a conclusão de outro, independentemente do resultado do primeiro.command1 ; command2
Primeiro command1
é executado, em primeiro plano, e quando terminar, command2
será executado.
Uma nova linha que não esteja em uma string literal ou após determinadas palavras-chave énãoequivalente ao operador ponto e vírgula. Uma lista de ;
comandos simples delimitados ainda é umlista- como no analisador do shell ainda deve continuar a ler os comandos simples que seguem um ;
comando simples delimitado antes de executar, enquanto uma nova linha pode delimitar uma lista inteira de comandos - ou lista de listas. A diferença é sutil, mas complicada: dado que o shell não tem imperativo prévio para leitura de dados após uma nova linha, a nova linha marca um ponto onde o shell pode começar a avaliar os comandos simples que já leu, enquanto um ;
ponto e vírgula faz não.
&
: Isso executará um comando em segundo plano, permitindo que você continue trabalhando no mesmo shell.command1 & command2
Aqui, command1
é iniciado em segundo plano e command2
começa a rodar em primeiro plano imediatamente, sem esperar command1
para sair.
Uma nova linha depois command1
é opcional.
A.2 Operadores lógicos
&&
: usado para construir listas AND, permite executar um comando somente se outro for encerrado com sucesso.command1 && command2
Aqui, command2
vai correr depois de command1
terminar eapenasif command1
foi bem-sucedido (se seu código de saída fosse 0). Ambos os comandos são executados em primeiro plano.
Este comando também pode ser escrito
if command1
then command2
else false
fi
ou simplesmente if command1; then command2; fi
se o status de retorno for ignorado.
||
: Usado para construir listas OR, permite executar um comando somente se outro for encerrado sem sucesso.command1 || command2
Aqui, command2
só será executado se command1
falhar (se retornar um status de saída diferente de 0). Ambos os comandos são executados em primeiro plano.
Este comando também pode ser escrito
if command1
then true
else command2
fi
ou de uma forma mais curta if ! command1; then command2; fi
.
Observe que &&
e ||
são associativos à esquerda; verPrecedência dos operadores lógicos do shell &&, ||Para maiores informações.
!
: Esta é uma palavra reservada que atua como o operador “not” (mas deve ter um delimitador), usada para negar o status de retorno de um comando - retorne 0 se o comando retornar um status diferente de zero, retorne 1 se retornar o status 0 . Também um NOT lógico para otest
utilitário.! command1 [ ! a = a ]
E um verdadeiro operador NOT dentro de Expressões Aritméticas:
$ echo $((!0)) $((!23))
1 0
A.3 Operador de tubo
|
: O operador pipe, ele passa a saída de um comando como entrada para outro. Um comando criado a partir do operador pipe é chamado degasoduto.command1 | command2
Qualquer saída impressa por
command1
é passada como entrada paracommand2
.|&
: Este é um atalho para2>&1 |
bash e zsh. Ele passa a saída padrão e o erro padrão de um comando como entrada para outro.command1 |& command2
A.4 Outra pontuação da lista
;;
é usado apenas para marcar o final de umdeclaração de caso. Ksh, bash e zsh também suportam ;&
passar para o próximo caso e ;;&
(não no ATT ksh) continuar e testar os casos subsequentes.
(
e )
estão acostumadoscomandos de grupoe execute-os em um subshell. {
e }
também agrupe comandos, mas não os inicie em um subshell. Veresta respostapara uma discussão sobre os vários tipos de parênteses, colchetes e colchetes na sintaxe do shell.
B. Operadores de redirecionamento
Definição POSIX de Operador de Redirecionamento
Na linguagem de comando shell, um token que executa uma função de redirecionamento. É um dos seguintes símbolos:
< > >| << >> <& >& <<- <>
Eles permitem que você controle a entrada e a saída de seus comandos. Eles podem aparecer em qualquer lugar dentro de um comando simples ou podem seguir um comando. Os redirecionamentos são processados na ordem em que aparecem, da esquerda para a direita.
<
: Fornece entrada para um comando.command < file.txt
O acima será executado command
no conteúdo de file.txt
.
<>
: o mesmo que acima, mas o arquivo está aberto emler + escrevermodo em vez desomente leitura:command <> file.txt
Se o arquivo não existir, ele será criado.
Esse operador raramente é usado porque os comandos geralmente sólerde seu stdin, emborapode ser útil em várias situações específicas.
>
: direciona a saída de um comando para um arquivo.command > out.txt
O acima irá salvar a saída de command
as out.txt
. Se o arquivo existir, seu conteúdo será sobrescrito e se não existir será criado.
Este operador também é frequentemente usado para escolher se algo deve ser impressoerro padrãoousaída padrão:
command >out.txt 2>error.txt
No exemplo acima, >
redirecionará a saída padrão e 2>
redirecionará o erro padrão. A saída também pode ser redirecionada usando 1>
mas, como esse é o padrão, 1
geralmente é omitido e escrito simplesmente como >
.
Portanto, para executar command
e file.txt
salvar sua saída out.txt
e quaisquer mensagens de erro, error.txt
você executaria:
command < file.txt > out.txt 2> error.txt
>|
: faz o mesmo que>
, mas substituirá o destino, mesmo que o shell tenha sido configurado para recusar a substituição (comset -C
ouset -o noclobber
).command >| out.txt
Se out.txt
existir, a saída de command
substituirá seu conteúdo. Se não existir, será criado.
>>
: faz o mesmo que>
, exceto que se o arquivo de destino existir, os novos dados serão anexados.command >> out.txt
Se out.txt
existir, a saída de command
será anexada a ele, após o que já estiver nele. Se não existir, será criado.
>&
: (de acordo com a especificação POSIX) quando cercado pordígitos(1>&2
) ou-
no lado direito (1>&-
) redireciona apenasumdescritor de arquivo ou fecha-o (>&-
).
Um >&
seguido por um número de descritor de arquivo é uma forma portátil de redirecionar um descritor de arquivo e >&-
é uma forma portátil de fechar um descritor de arquivo.
Se o lado direito deste redirecionamento for um arquivo, leia a próxima entrada.
>&
,&>
,>>&
e&>>
: (leia também acima) Redireciona o erro padrão e a saída padrão, substituindo ou anexando, respectivamente.command &> out.txt
Tanto o erro padrão quanto a saída padrão command
serão salvos em out.txt
, sobrescrevendo seu conteúdo ou criando-o se não existir.
command &>> out.txt
Como acima, exceto que, se out.txt
existir, a saída e o erro command
serão anexados a ele.
A &>
variante se origina em bash
, enquanto a >&
variante vem de csh (décadas antes). Ambos entram em conflito com outros operadores shell POSIX e não devem ser usados em sh
scripts portáteis.
<<
: Um documento aqui. Muitas vezes é usado para imprimir strings multilinhas.command << WORD Text WORD
Aqui,
command
vai levar tudo até encontrar a próxima ocorrência deWORD
,Text
no exemplo acima, como input . EmboraWORD
seja frequentementeEoF
ou suas variações, pode ser qualquer string alfanumérica (e não apenas) que você desejar. Quando qualquer parte deWORD
é citada ou escapada, o texto no documento here é tratado literalmente e nenhuma expansão é realizada (em variáveis, por exemplo). Se não estiver entre aspas, as variáveis serão expandidas. Para mais detalhes, consulte omanual do bash.Se você deseja canalizar a saída
command << WORD ... WORD
diretamente para outro comando ou comandos, você deve colocar o canal na mesma linha que<< WORD
, não pode colocá-lo após o WORD final ou na linha seguinte. Por exemplo:command << WORD | command2 | command3... Text WORD
<<<
: aqui strings, semelhantes aos documentos aqui, mas destinadas a uma única linha. Eles existem apenas na porta Unix ou rc (de onde se originou), zsh, algumas implementações de ksh, yash e bash.command <<< WORD
Tudo o que é fornecido como WORD
é expandido e seu valor é passado como entrada para command
. Isso geralmente é usado para passar o conteúdo de variáveis como entrada para um comando. Por exemplo:
$ foo="bar"
$ sed 's/a/A/' <<< "$foo"
bAr
# as a short-cut for the standard:
$ printf '%s\n' "$foo" | sed 's/a/A/'
bAr
# or
sed 's/a/A/' << EOF
$foo
EOF
Alguns outros operadores ( >&-
, x>&y
x<&y
) podem ser usados para fechar ou duplicar descritores de arquivo. Para obter detalhes sobre eles, consulte a seção relevante do manual do seu shell (aquipor exemplo para bash).
Isso cobre apenas os operadores mais comuns de shells do tipo Bourne. Alguns shells possuem alguns operadores de redirecionamento adicionais próprios.
Ksh, bash e zsh também possuem construções <(…)
e >(…)
( somente =(…)
esta última zsh
). Estes não são redirecionamentos, massubstituição de processo.
Responder2
Aviso sobre '>'
Iniciantes em Unix que acabaram de aprender sobre redirecionamento de E/S ( <
e >
) geralmente tentam coisas como
comando…Arquivo de entrada>o_mesmo_arquivo
ou
comando… <arquivo >o_mesmo_arquivo
ou, quase equivalentemente,
gatoarquivo|comando… >o_mesmo_arquivo
( grep
, sed
, cut
, sort
e spell
são exemplos de comandos que as pessoas ficam tentadas a usar em construções como essas.) Os usuários ficam surpresos ao descobrir que esses cenários resultam no esvaziamento do arquivo.
Uma nuance que não parece ser mencionada na outra resposta pode ser encontrada escondida na primeira frase doRedirecionamentoSeção defestança(1):
Antes de um comando ser executado, sua entrada e saída podem serredirecionado usando uma notação especial interpretada pelo shell.
As primeiras cinco palavras devem estar em negrito, itálico, sublinhado, ampliadas, piscantes, coloridas em vermelho e marcadas com um ícone, para enfatizar o fato de que o shell executa o(s) redirecionamento(s) solicitado(s)
antes do comando ser executado. E lembre-se também
O redirecionamento da saída faz com que o arquivo… seja aberto para gravação…. Se o arquivo não existir ele será criado; se existir, será truncado para tamanho zero.
Então, neste exemplo:
sort roster > roster
o shell abre o
roster
arquivo para gravação, truncando-o (ou seja, descartando todo o seu conteúdo), antes que osort
programa comece a ser executado. Naturalmente, nada pode ser feito para recuperar os dados.Alguém poderia ingenuamente esperar que
tr "[:upper:]" "[:lower:]" < poem > poem
pode ser melhor. Como o shell lida com redirecionamentos da esquerda para a direita, ele abre
poem
para leitura (para atr
entrada padrão de) antes de abri-lo para gravação (para a saída padrão). Mas isso não ajuda. Embora essa sequência de operações produza dois identificadores de arquivo, ambos apontam para o mesmo arquivo. Quando o shell abre o arquivo para leitura, o conteúdo ainda está lá, mas ainda é destruído antes que o programa seja executado.
Então o que fazer sobre isso?
As soluções incluem:
Verifique se o programa que você está executando tem seu próprio recurso interno para especificar para onde vai a saída. Isso geralmente é indicado por um token
-o
(ou--output=
). Em particular,sort -o roster roster
é aproximadamente equivalente a
sort roster > roster
exceto que, no primeiro caso, o
sort
programa abre o arquivo de saída. E é inteligente o suficiente para não abrir o arquivo de saída atédepoisele leu todos os arquivos de entrada.Da mesma forma, pelo menos algumas versões
sed
têm um-i
(editareun place) opção que pode ser usada para gravar a saída de volta no arquivo de entrada (novamente,depoistodas as entradas foram lidas). Editores comoed
/ex
,, e / permitem ao usuário editar um arquivoemacs
de texto e salvar o texto editado no arquivo original. Observe que (pelo menos) pode ser usado de forma não interativa.pico
vi
vim
ed
vi
tem um recurso relacionado. Se você digitar , o conteúdo do buffer de edição será gravado em:%!command
Entercommand
, leia a saída e insira-a no buffer (substituindo o conteúdo original).
Simples mas efetivo:
comando…Arquivo de entrada>arquivo temporário && mvarquivo temporário Arquivo de entrada
Isto tem a desvantagem de que, se
input_file
for um link, ele (provavelmente) será substituído por um arquivo separado. Além disso, o novo arquivo será de sua propriedade, com proteções padrão. Em particular, isto acarreta o risco de que o arquivo acabe sendo legível por todos, mesmo que o originalinput_file
não foi.Variações:
command … input_file > temp_file && cp temp_file input_file && rm temp_file
que ainda (potencialmente) deixará otemp_file
legível pelo mundo. Melhor ainda:cp input_file temp_file && command … temp_file > input_file && rm temp_file
Eles preservam o status do link, o proprietário e o modo (proteção) do arquivo, potencialmente ao custo do dobro de E/S. (Talvez seja necessário usar uma opção como-a
ou-p
oncp
para solicitar a preservação dos atributos.)command … input_file > temp_file &&
cp --attributes-only --preserve=all input_file temp_file &&
mv temp_file input_file
(dividido em linhas separadas apenas para facilitar a leitura) Isso preserva o modo do arquivo (e, se você for root, o proprietário), mas torna-o propriedade de você (se você não for root) e o torna um novo, arquivo separado.
Este blog (edição de arquivos “no local”) sugere e explica
{rmArquivo de entrada && comando… >Arquivo de entrada; } <Arquivo de entrada
Isto exige que o
command
ser capaz de processar entrada padrão (mas quase todos os filtros podem). O próprio blog chama isso de brincadeira arriscada e desencoraja seu uso. E isso também criará um arquivo novo e separado (não vinculado a nada), de sua propriedade e com permissões padrão.O pacote moreutils possui um comando chamado
sponge
:comando…Arquivo de entrada| esponjao_mesmo_arquivo
Veresta respostaPara maiores informações.
Aqui está algo que me surpreendeu completamente: erro de sintaxe diz:
[A maioria dessas soluções] falhará em um sistema de arquivos somente leitura, onde “somente leitura” significa que seu
$HOME
vaiser gravável, mas/tmp
serásomente leitura(por padrão). Por exemplo, se você possui Ubuntu e inicializou no Console de recuperação, esse é normalmente o caso. Além disso, o operador here-document<<<
também não funcionará lá, pois precisa/tmp
serler escrever porque ele gravará um arquivo temporário lá também.
(cf.essa questãoinclui umastrace
saída 'd)
O seguinte pode funcionar nesse caso:
- Apenas para usuários avançados:
Se for garantido que seu comando produza a mesma quantidade de dados de saída que há de entrada (por exemplo,
sort
, outr
sema opção-d
ou-s
), você pode tentarcomando…Arquivo de entrada| dd de =o_mesmo_arquivoconv=notrunc
Veresta resposta eesta respostapara obter mais informações, incluindo uma explicação do acima, e alternativas que funcionam se for garantido que seu comando produza a mesma quantidade de dados de saída que há de entradaou menos(por exemplo,grep
, oucut
). Estas respostas têm a vantagem de não necessitarem de espaço livre (ou necessitarem de muito pouco). As respostas acima do formulário exigem claramente que haja espaço livre suficiente para que o sistema possa armazenar todo o arquivo de entrada (antigo) e o arquivo de saída (novo) simultaneamente; isso não é obviamente verdade para a maioria das outras soluções (por exemplo, e ) também. Exceção: provavelmente exigirá muito espaço livre, porque precisa ler todas as suas entradas antes de poder gravar qualquer saída e provavelmente armazena em buffer a maioria, senão todos, os dados em um arquivo temporário.command … input_file > temp_file && …
sed -i
sponge
sort … | dd …
sort
- Apenas para usuários avançados:
comando…Arquivo de entrada1<>o_mesmo_arquivo
pode ser equivalente àdd
resposta acima. A sintaxe abre o arquivo nomeado no descritor de arquivon<> file
n
tanto para entrada quanto para saída, sem truncá-lo – uma espécie de combinação de e . Nota: Alguns programas (por exemplo, e ) podem recusar a execução neste cenário porque podem detectar que a entrada e a saída são o mesmo arquivo. Vern<
n>
cat
grep
esta resposta para uma discussão sobre o acima, e um script que faz esta resposta funcionar se for garantido que seu comando produza a mesma quantidade de dados de saída que há de entradaou menos.
Aviso: não testei o script de Peter, então não garanto isso.
Então, qual foi a pergunta?
Este tem sido um tópico popular na U&L; é abordado nas seguintes questões:
- Existe uma maneira de modificar um arquivo no local?
- Como posso
iconv
substituir o arquivo de entrada pela saída convertida? - Por que o comando
shuf file > file
deixa um arquivo vazio? - Posso ler e gravar no mesmo arquivo no Linux sem sobrescrevê-lo?
- Redirecionar para o mesmo arquivo do arquivo de origem processado pelo comando
- Por que este
sort
comando me fornece um arquivo vazio? - Redirecionando
tr
stdout para um arquivo - grep: arquivo de entrada 'X' também é a saída
- Os operadores de redirecionamento abrem descritores de arquivos em paralelo?
- Redirecionamento não sobrescrevendo o arquivo, mas apenas produzindo um arquivo em branco
… e isso sem contar o Superusuário ou o Ask Ubuntu. Incorporei muitas informações das respostas às perguntas acima aqui nesta resposta, mas não todas. (Ou seja, para obter mais informações, leia as perguntas listadas acima e suas respostas.)
PS eu tenhonãoafiliação ao blog que citei acima.
Responder3
Mais observações sobre ;
, &
e(
)
Observe que alguns dos comandos da resposta de Terdon podem ser nulos. Por exemplo, você pode dizer
command1 ;
(com nenhum
command2
). Isto é equivalente acommand1
(ou seja, ele simplesmente é executado
command1
em primeiro plano e aguarda a conclusão. Da mesma forma,command1 &
(sem
command2
) será iniciadocommand1
em segundo plano e emitirá outro prompt de shell imediatamente.Por outro lado,
command1 &&
,command1 ||
ecommand1 |
não fazem sentido. Se você digitar um destes, o shell (provavelmente) assumirá que o comando continua em outra linha. Ele exibirá o prompt do shell secundário (continuação), que normalmente é definido como>
e continuará lendo. Em um script de shell, ele apenas lerá a próxima linha e a acrescentará ao que já leu. (Cuidado: isso pode não ser o que você deseja que aconteça.)Nota: algumas versões de alguns shells podem tratar comandos incompletos como erros. Nesses casos (ou, na verdade, emqualquercaso você tenha um comando longo), você pode colocar uma barra invertida (
\
) no final de uma linha para dizer ao shell para continuar lendo o comando em outra linha:command1 && \ command2
ou
find starting-directory -mindepth 3 -maxdepth 5 -iname "*.some_extension" -type f \ -newer some_existing_file -user fred -readable -print
Como diz terdon,
(
e)
pode ser usado para agrupar comandos. A afirmação de que “não são realmente relevantes” para essa discussão é discutível. Alguns dos comandos na resposta de Terdon podem ser comandosgrupos. Por exemplo,( command1 ; command2 ) && ( command3; command4 )
faz isso:
- Corra
command1
e espere terminar. - Então, independentemente do resultado da execução do primeiro comando, execute
command2
e espere que ele termine. Então, se
command2
tiver sucesso,- Corra
command3
e espere terminar. - Então, independentemente do resultado da execução desse comando, execute
command4
e espere que ele termine.
Se
command2
falhar, pare de processar a linha de comando.- Corra
- Corra
Fora dos parênteses,
|
liga-se com muita força, entãocommand1 | command2 || command3
é equivalente a
( command1 | command2 ) || command3
e
&&
e||
amarre com mais força que;
, entãocommand1 && command2 ; command3
é equivalente a
( command1 && command2 ) ; command3
ou seja,
command3
será executado independentemente do status de saída decommand1
e/oucommand2
.