Como `>` e `>>` funcionam?

9

Eu tentei revum arquivo e depois o canalizei, cat > same_filemas estava se transformando em um arquivo em branco.

Enquanto eu tentei rev file.txt | cat > file2.txt && mv file.txt file2.txt;, funcionou.

Até rev file.txt | cat >> file.txt;funcionou.

Mas quando eu tentei rev file.txt | cat > file.txt, falhou.

Vintux
fonte
Você também pode deixar catfora como este: rev file.txt > file2.txt && mv file2.txt file.txt. Este é um uso supérfluo decat . Ao deixá-lo de fora, você poupa a geração de um processo extra.
Matega

Respostas:

19

O básico que você precisa entender nesse caso entre as duas maneiras de redirecionar (> e >>) é:

>

Redireciona e substitui as informações para as quais elas foram apontadas. Isso acontece ao receber qualquer informação através do canal "|"

>>

Redireciona e concatena as informações para as quais foi apontada. Isso acontece ao receber qualquer informação através do canal "|"

Nos dois casos, se o arquivo não existir, ele será criado. Somente em ">>" as informações serão concatenadas se você executá-las novamente no mesmo arquivo. Com ">" você simplesmente substituiria tudo o que fez na primeira execução.

Mas aqui está o problema ao usar o mesmo arquivo de entrada que o arquivo de saída. Nesse caso específico, se você usar ">", removeria as informações que a parte "entrada" precisa analisar, uma vez que o arquivo de saída estaria "substituindo-o". Então em:

rev file.txt | cat > file.txt

O que realmente está acontecendo na "explicação em câmera lenta" é:

  1. revse prepara para reverter o conteúdo file.txte enviá-lo para o canal
  2. Enquanto revestá enviando as informações para o pipe, ele o envia diretamente para cat.
  3. Enquanto catestiver recebendo as informações, ela será aplicada automaticamente ao file.txtque foi definido.
  4. A palavra-chave aqui é "while", porque tudo está acontecendo ao mesmo tempo. Por favor, veja os excelentes comentários abaixo de Emil para entender melhor essa parte.
  5. catnão esperará para revcanalizar o arquivo inteiro. Ele simplesmente começará no minuto em que a primeira parte da informação chegar, o que significa que, dependendo de qual símbolo você usou, ela abrirá uma conexão file.txt.
  6. Nesse caso, desde que você usou o > em vez de >> , o shell truncará o arquivo de saída, o que significa que ele abrirá e limpará as informações file.txtenquanto aguarda a chegada das novas informações. Com >>, ele abriria uma conexão file.txte aguardaria novas informações na última linha detectada.
  7. Como a informação já foi limpa file.txtcom > , revtentaria fazer seu trabalho e não obteria nada porque catexcluía tudo em preparação para a nova informação.

Então, por que os outros trabalham depois de ler o acima? Por causa disso:

rev file.txt | cat > file2.txt && mv file.txt file2.txt

Aqui você está direcionando para o gato que está enviando as informações para outro arquivo. Nesse caso, o arquivo de entrada processado file.txtnão é o mesmo que o arquivo de saída file2.txt. Depois que você está literalmente substituindo o todo file2.txtcom file.txt, por isso, todo o processo feito pelo catfoi excluída. Basicamente, toda a linha poderia ser simplificada, cp file.txt file2.txtporque ela está fazendo a mesma coisa, pois file2.txtno final perde revo mvcomando e é sobrescrita .

rev file.txt | cat >> file.txt

Nesse caso, você está concatenando as informações para o mesmo arquivo. Portanto, ele está apenas abrindo uma conexão com esse arquivo, mas não apagando as informações como vistas com um único > . O resultado final deve ser a informação original mais a informação invertida.

Luis Alvarado
fonte
5
O arquivo não é truncado pelo gato. Ele é truncado pelo shell antes mesmo de qualquer um dos comandos no pipeline ser iniciado.
Emil Jerabek
Correto, estava procurando palavras mais fáceis de explicar. Como é um pouco difícil de explicar se o OP não sabe o que é um shell e tudo isso. Tentando torná-lo o mais "amigável" possível.
Luis Alvarado
11
Bem, realmente não importa que isso seja feito pelo shell, mas que o momento que você apresenta está errado. O truncamento não ocorrerá na etapa 6, mas na etapa 0. rev file.txt | cat --bogus-option > file.txttambém truncará o arquivo, mesmo que o gato não tente abri-lo.
Emil Jerabek
@ EmilJeřábek você está correto. Mesmo assim, os usuários que não sabem como se comportam terão mais facilidade se formos passo a passo apenas com os comandos. Além disso, seu exemplo ainda está enviando as informações para o mesmo arquivo; portanto, o bash lerá toda a linha, verá a saída e ainda abrirá e truncará. O erro é simplesmente a saída do stderr para o stdout.
44675 Luis Alvarado
4
Veja também moreutils , uma fantástica coleção de ferramentas (disponível no repositório de pacotes como moreutils) que inclui spongeuma ferramenta projetada especificamente para a maneira de substituir um arquivo de entrada. Por exemplo, a rev file.txt >file2.txt && mv file2.txt file.txtsolução alternativa se tornaria rev file.txt | sponge file.txt, o que funcionará corretamente mesmo quando já houver algo nomeado file2.txt.
Daniel Wagner
9

Quando o shell vê o redirecionamento, ele abre os arquivos relevantes primeiro, antes de executar qualquer um dos comandos envolvidos. Assim, quando você faz:

foo file.txt | bar > file.txt

O redirecionamento para file.txtfaz com que seja truncado antes de foo ser executado e pode ser lido file.txt. Em uma nota lateral, é por isso que você não pode fazer:

sed 'blah' file.txt > file.txt

E por que sedtem uma opção de edição no local.

Por fim, fazendo:

.. | cat > file.txt

é um uso inútil de gato , especialmente se você estiver tentando ler file.txtmais cedo.

Se você deseja reverter um arquivo no local, não há atalhos . Você pode usar os truques sedou awkcom a edição no local.

muru
fonte
3

>é um redirecionador (operador) enviando a saída para outra coisa
(entrada do próximo comando, impressora ..)

No seu caso, a saída vai para um arquivo file.txt, se esse arquivo já existir, será sobrescrito, caso contrário, ele será criado.

>>é um operador de acréscimo, se file.txtjá existir, a saída será anexada ao final do arquivo. se o arquivo não existir, ele será criado e a saída gravada no novo arquivo, igual a >(redirecionador).

Ken Mollerup
fonte
O OP parece ter entendido isso. A confusão parece ter origem apenas no mesmo arquivo que está nos dois lados dos operadores >e >>.
bzlm
0

Você pode usar o Vim no modo Ex:

ex -sc '%!rev' -cx file.txt
  1. % selecione todas as linhas

  2. ! comando de execução

  3. x salvar e fechar

Steven Penny
fonte