Comando e eco do gato

14

Eu gostaria de concatenar a saída do eco com o conteúdo de um arquivo. Eu tentei o seguinte comando:

echo "abc" | cat 1.txt > 2.txt

mas o 2.txtarquivo contém apenas o conteúdo de 1.txt. Por que isso não funciona?

Ringger81
fonte
3
Programas como catapenas leem da entrada padrão se não tiverem nenhum argumento de nome de arquivo.
Barmar

Respostas:

23

Não funciona porque o catprograma na sequência de tubulação não foi instruído a ler a echosaída do programa a partir da entrada padrão.

Você pode usar -como um nome de pseudo arquivo para indicar entrada padrão para cat. Em man catuma instalação do msys2:

EXAMPLES
       cat f - g
              Output f's contents, then standard input, then g's contents.

Então tente

echo "abc" | cat - 1.txt > 2.txt

em vez de.

mvw
fonte
21

Conforme observado por outras pessoas, seu comando original falha porque cat 1.txtdesconsidera sua entrada padrão. Indique que esse deve ser o primeiro argumento ( cat - 1.txt) ou use o redirecionamento de bloco para redirecionar echo abc e cat 1.txt juntos. A saber:

{ echo abc; cat 1.txt; } > 2.txt 

Trecho relevante do manual ( man bash):

Comandos
compostos Um comando composto é um dos seguintes. Na maioria dos casos, uma lista na descrição de um comando pode ser separada do restante do comando por uma ou mais novas linhas e pode ser seguida por uma nova linha no lugar de um ponto e vírgula.

(Lista)

    A lista é executada em um ambiente subshell (consulte AMBIENTE DE EXECUÇÃO DE COMANDO abaixo). As atribuições variáveis ​​e os comandos internos que afetam o ambiente do shell não permanecem em vigor após a conclusão do comando. O status de retorno é o status de saída da lista.

{Lista; }

    A lista é simplesmente executada no ambiente atual do shell.  A lista deve ser finalizada com uma nova linha ou ponto e vírgula. Isso é conhecido como um comando de grupo . O status de retorno é o status de saída da lista . Observe que, diferentemente dos metacaracteres (e ), {e }são palavras reservadas, devem ocorrer onde uma palavra reservada pode ser reconhecida. Como eles não causam uma quebra de palavra, eles devem ser separados da lista por espaços em branco ou outro metacaractere do shell.

A primeira opção (ambiente subshell) tem vários efeitos colaterais, a maioria, se não todos, são irrelevantes para o seu cenário; no entanto, se você precisar apenas redirecionar a saída de vários comandos, é preferível a opção 2 aqui (comando de grupo).

Nubarke
fonte
7
( echo "abc"; cat 1.txt ) > 2.txt

Você canalizou a saída de eco para cat, mas cat não tinha utilidade para entrada e a ignorou. Agora, os comandos são executados um após o outro e sua saída é agrupada (parênteses) e direcionada para 2.txt.

Gerard H. Pille
fonte
1
Essa resposta pode ser melhorada, explicando como funciona e por que a tentativa original do OP não funciona.
Bob
OK, tentei.
Gerard H. Pille 13/01
5
Um subshell não é expressamente necessário aqui, talvez seja melhor usar um comando de grupo. Veja minha resposta para mais detalhes.
Nubarke
Ah, mas eu nunca usaria o bash.
Gerard H. Pille
1
@ GerardH.Pille: Embora a resposta de Daniel cite bash(1), ela descreve o comportamento que todo shell compatível com POSIX deve suportar.
G-Man diz 'Reinstate Monica'
2

Seu comando cat 1.txtnão faz nada com a saída de echo "abc".

Em vez disso: (echo "abc"; cat 1.txt) > 2.txt gravará a saída dos dois comandos no 2.txt.

muclux
fonte
Esta resposta pode ser melhorada, explicando como a alternativa sugerida funciona.
Bob
1

Em qualquer shell POSIX, você pode usar a substituição de comando para usar cat filecomo entrada para echo:

echo $(cat file1.txt) "This Too"

No Bash, você pode usar a substituição do processo e usar o eco como outro "arquivo" para cat, como em:

cat file1.txt <(echo This Too)

e depois canalize ou redirecione a saída como achar melhor.

Como todas as outras respostas dizem, cat ignora stdin se tiver um arquivo para analisar. (Eu também gosto das respostas de Daniel & mvw, +1 para elas)

Xen2050
fonte
1
Essa resposta pode ser melhorada, explicando por que a tentativa original do OP não funciona (e, portanto, por que isso é necessário).
Bob
1
A <(command)construção é uma extensão do bash. Não é POSIX, portanto você não pode confiar nele em scripts que deveriam ser executados /bin/sh.
Rhialto apoia Monica
0

Apenas um palpite, mas parece que você tem um processo repetível, que é um bom candidato para um alias ou uma função. Aliases geralmente são atalhos para chamar comandos bash, como abreviação, em um único fluxo de entrada como argumento (s).

alias hg="history | grep"

Entretanto, nesse caso, uma função seria mais legível, pois você está combinando vários fluxos de entrada discretos (2) e vários comandos bash. Você tem dois argumentos, o primeiro sendo uma sequência e o outro um caminho de arquivo. No final, você deseja que o resultado seja gravado no fluxo de saída stdout.

Em um prompt da CLI, digite este:

# ecat()        
{
echo ${1}
cat ${2}
}

Sua função é denominada ecat, que é memorável.

Agora você pode chamar como

ecat "abc" 1.txt

Para acrescentar, basta fornecer um destino de saída diferente ao stdout:

ecat "abc" 1.txt >> 2.txt

O operador de redirecionamento de acréscimo '>>' adicionará a saída ao final do arquivo especificado.

Se você gosta, anexe seu arquivo ~ / .bashrc para reutilização.

declare -f ecat >> ~/.bashrc

Isso também significa que você pode decorar, etc., dentro da sua definição de função.

Também é uma boa idéia evitar que os arquivos sejam substituídos adicionando-os ao seu ~ / .bashrc

set noclobber
FrDarryl
fonte
2
Para que sua função se comporte corretamente, você deve usar "$1"e "$2". Nesse contexto, o aparelho não faz nenhum bem. Ver ${name}não significa o que você pensa que faz .
G-Man diz 'Reinstate Monica'
1
Como a noclobbersugestão responde à pergunta em questão? (Também não estou convencido de que seja um bom conselho - modificar o comportamento global tende a quebrar scripts / conselhos / práticas construídas com os padrões em mente).
Charles Duffy
0

O código a seguir também funcionará:

echo abc >> 1.txt && cat 1.txt > 2.txt

A saída do echo abc será anexado ao 1.txt com >> Depois que o && dir-lo para executar o próximo conjunto de comandos que irá 1.txt gato e, em seguida, saída para 2.txt . Basicamente, ele anexa a saída do primeiro comando em 1.txt e envia a saída de 1.txt para 2.txt.

Se você deseja que o abc apareça primeiro, use o seguinte código:

echo abc >> 2.txt && cat 1.txt >> 2.txt
Nasir Riley
fonte
1
Isso irá (1) colocar abcna parte inferior de 2.txt; a pergunta quer no topo. (2)  modificar o 1.txtarquivo; isso é inaceitável.
G-Man diz 'Reinstate Monica'
Onde isso diz isso? Ringger81 nunca especificou onde, em 2.txt, ele queria que o abc aparecesse. Você está assumindo coisas que a pergunta nunca afirma.
Nasir Riley
(1) OK, você eleva um ponto válido no # 1. Enquanto a pergunta menciona "saída do eco" antes do "conteúdo de um arquivo" no texto e, em seguida, coloca o comando echoantes do catno exemplo, suponho que nunca exatamente, explicitamente , diga que deseja a saída do eco antes do conteúdo do arquivo de entrada. Parece que a maioria das pessoas interpretou dessa maneira. (2)  1.txté um arquivo de entrada. A questão não diz nada sobre modificação 1.txt. O fato de que os arquivos de entrada não devem ser modificados é desnecessário.
G-Man diz 'Reinstate Monica'
Entendo seu ponto de vista sobre não modificar o arquivo de imputação. Meu segundo código alcançará o efeito desejado sem fazer isso.
Nasir Riley
1
Abrindo um arquivo, anexando-o, fechando-o , abrindo-o novamente, anexando-o novamente ... por que fazer isso em vez de apenas abri-lo uma vez e manter o redirecionamento no lugar para as duas operações?
Charles Duffy