Como você usa o redirecionamento de saída em combinação com here-documents e cat?

56

Digamos que eu tenho um script que quero canalizar para outro comando ou redirecionar para um arquivo (canalizando shpara os exemplos). Suponha que eu estou usando o bash.

Eu poderia fazer isso usando echo:

echo "touch somefile
echo foo > somefile" | sh

Eu também poderia fazer quase a mesma coisa usando cat:

cat << EOF
touch somefile
echo foo > somefile
EOF

Porém, se eu substituir "EOF" por "EOF | sh", ele simplesmente achará parte do heredoc.

Como posso fazer com que o cattexto saia do stdin e o direcione para um local arbitrário?

strugee
fonte
touchexiste, a menos que exista, o que exatamente você quer? é apenas ler o arquivo de entrada e redirecionar para outro com stdout?
Rahul Patil
2
@RahulPatil é claro que é inútil. Eu só queria um exemplo com mais de uma linha, para ilustrar melhor o heredoc. E olhe o exemplo usando echo- eu estava pensando qual seria o equivalente disso cat.
strugee
Seu exemplo é criar um shscript com várias strings e passá-lo diretamente para sh. Encontrei o seu Q procurando passar a saída de texto de vários comandos, incluindo um documento HERE, diretamente para um comando. Qual é o que o segundo exemplo da resposta de Ash faz.
Dave X

Respostas:

91

Existem várias maneiras de fazer isso. O mais simples é provavelmente o seguinte:

cat <<EOF | sh
touch somefile
echo foo > somefile
EOF

Outro, que é uma sintaxe melhor na minha opinião:

(
cat <<EOF
touch somefile
echo foo > somefile
EOF
) | sh

Isso funciona também, mas sem o subshell:

{
cat <<EOF
touch somefile
echo foo > somefile
EOF
} | sh

Mais variações:

cat <<EOF |
touch somefile
echo foo > somefile
EOF
  sh

Ou:

{ cat | sh; } << EOF
touch somefile
echo foo > somefile
EOF

A propósito, espero que o uso da catsua pergunta seja um espaço reservado para outra coisa. Caso contrário, retire-o, assim:

sh <<EOF
touch somefile
echo foo > somefile
EOF

O que poderia ser simplificado para isso:

sh -c 'touch somefile; echo foo > somefile'

ou:

sh -c 'touch somefile
echo foo > somefile'

Redirecionando a saída em vez da tubulação

sh >out <<EOF
touch somefile
echo foo > somefile
EOF

Usando catpara obter o equivalente a echo test > out:

cat >out <<EOF
test
EOF

Vários documentos aqui

( cat; echo ---; cat <&3 ) <<EOF 3<<EOF2
hi
EOF
there
EOF2

Isso produz a saída:

hi
---
there

Aqui está o que está acontecendo:

  • O shell vê ( ... )e executa os comandos incluídos em um subshell.
  • O gato e o eco são bastante simples. O cat <&3diz para executar gato com descritor de arquivo (fd) 0 (stdin) redirecionadas de fd 3; em outras palavras, identifique a entrada de fd 3.
  • Antes de (...)iniciar, o shell vê os dois documentos aqui redirecionarem e substituírem fd 0 ( <<EOF) e fd 3 ( 3<<EOF2) pelo lado de leitura dos pipes
  • Depois que o comando inicial é iniciado, o shell lê seu stdin até que o EOF seja alcançado e o envia para o lado de gravação do primeiro canal
  • Em seguida, faz o mesmo com o EOF2 e o lado de gravação do segundo canal
cinza
fonte
dado o penúltimo exemplo, você pode dar um exemplo com redirecionamento stdout em vez de canalizar?
strugee
Editei a resposta com um exemplo de redirecionamento; este é o formulário que você deseja editar? Caso contrário, você pode apenas dar a primeira linha dessa parte para esclarecer?
ash
11
Pode ajudar a entender como o shell processa isso. Ao avaliar a linha de comando e encontrar o << EOF, ele lê da entrada padrão até encontrar uma linha com apenas EOF ou final de entrada. Tudo o mais na linha de comando original que ainda não foi processado continua sendo processado. Assim, por exemplo, é possível fazer algo assim: (cat; echo ---; exec <&3; cat) <<EOF 3<<EOF2 >oute depois fornecer esse comando com dois blocos aqui seguidos.
ash
Sua explicação sobre o processamento de shell foi interessante, mas na minha cabeça :) O que eu queria saber era o que seria o catequivalente a echo test > outusar um heredoc. Considerando que o seu exemplo dado adicionou um redirecionamento no final do canal.
strugee
11
@OlivierDulac - adicionei o exemplo heredoc múltiplo à resposta.
ash
1

Eu só quero salientar que o uso meowé tão válido quanto EOF.

Este script será anexado Meow!a um arquivo chamado cat:

#!/bin/sh
cat <<meow>> cat
Meow!
meow

Salve como catse torne-o executável com chmod +x catse execute-o com ./cats:

$ ./cats
$ cat cat
Meow!
$ ./cats
$ cat cat
Meow!
Meow!

Explicação:

  • cat <<meowé a sintaxe do documento aqui . Ele instrui o script a pegar o bloco de texto que segue esta linha, até encontrar a sequência meow. O conteúdo será emitido (ou enviado junto).
  • >> catcanaliza para o arquivo nomeado cat.
  • Usar em >vez de >>substituir o arquivo em vez de anexá-lo.
  • Meow!é o conteúdo do documento aqui .
  • meowé o marcador final do documento aqui . O conteúdo é, com o uso de >>, anexado a cat.

Piping para stdout e para um arquivo:

Para executar a tubulação solicitada, nenhum documento aqui é necessário.

catnão pode produzir texto nem repassá-lo, mas teeé uma combinação perfeita para o que você está pedindo:

echo echo | tee tee

Isso produzirá a string echoe gravará echoem um arquivo chamado tee.

Você também pode passar a saída cat, se isso fizer parte do requisito, com:

echo echo | tee tee | cat </dev/stdin

Ou apenas:

echo echo | tee tee | cat

Conteúdo do arquivo:

$ cat tee
echo
Alexander
fonte
11
Isso realmente não responde à pergunta. Também >não cria canos como sua última bala implica.
strugee
2
@strugee, >pode criar pipes zshquando o mesmo fd é redirecionado várias vezes como em echo foo >&1 > teeor echo foo > tee | cat, onde zshimplementa um interno teepara alimentar a saída de echoambos cate do teearquivo.
Stéphane Chazelas
Atualizei minha resposta para melhor responder à pergunta.
Alexander