Esclarecimento sobre comportamento de shell script junto com pipe

4

Eu preciso entender o comportamento do seguinte script de shell.

#!/bin/bash
echo "First more"
more $1

echo "First echo"
echo $1

echo "Second more"
more $1

Quando eu executo o seguinte comando:

echo dir1 | bash script.sh

Eu recebo a seguinte saída

First more
dir1
First echo

Second more

Por que o echo e o segundo more não obtêm acesso ao conteúdo de $1 ?

Quando eu executo o seguinte comando:

echo dir1 | bash script.sh dir2

Eu recebo o seguinte comando

First more

dir1

*** dir2: directory ***

First echo
dir2
Second more

*** dir2: directory ***

dir2 é passado para todos os comandos, mas mais apenas imprime dir1 , mas considera dir2 como um diretório.

    
por Manoj 07.05.2013 / 08:33

2 respostas

7

Você está confundindo argumentos e entradas padrão. Dados de tubulação para um programa não são equivalentes a dar argumentos de linha de comando.

No seu primeiro caso, você não está transmitindo argumentos para o seu script, apenas alimentando os dados através de seu fluxo de entrada padrão. Portanto, $1 não é definido durante toda a duração do script.
A primeira invocação de more , portanto, não possui parâmetro e exibe a entrada padrão. Isso exibe o que você tinha canalizado lá ( dir1 , como texto). O echo subseqüente imprime apenas uma nova linha, pois não obtém nada para imprimir, e o último more não tem mais nada para imprimir - a entrada padrão foi "drenada" pela primeira.

No segundo caso, você passa um argumento. Então $1 tem o valor dir2 no script. A mesma coisa acontece, exceto que o primeiro more ambos:

  • páginas por meio da entrada padrão
  • tenta exibir o arquivo dir2 e erros, pois esse é um diretório

O eco faz o que é esperado, dado que $1 contém dir2 e os últimos% more apenas erros em dir2 - não tem nada a ler da entrada padrão.

    
por 07.05.2013 / 08:53
4

A diferença está em " Argumentos " VS " Entrada padrão ".

Quando você executa echo dir1 | bash script.sh , o argumento $1 no seu script.sh está sempre vazio, pois nenhum argumento é dado a ele (tente adicionar um set -x no início e você veja na saída de depuração). O dir1 que é ecoado vem da entrada padrão quando o comando more lê stdin se nenhum argumento é dado (lembre-se $1 está vazio).

Como o cmd1 | cmd2 funciona

Ao usar o pipe:

  1. cmd2 é um subprocesso de cmd1 .
  2. o stdin de cmd2 é "plugado" no stdout de cmd1 .

Como o linux stdio lib oferece um fluxo em buffer através do descritor de arquivo, o conteúdo stdin será consumido (ou seja, somente uma vez) somente quando o stdin for aberto .

Passo a passo cmd1 | cmd2 workflow

Exemplo de comando:

echo dir1 | (echo "a" ; read stdinvalue; echo "$stdinvalue")

  1. echo dir1 | : escreve " dir1\n " no stdout do primeiro comando que não é ecoado mas armazenado em buffer através do stdio e disponível para subprocessar via stdin.
  2. echo "a" : escreva " a\n " no stdout; não lê stdin! , então a string " dir1\n " ainda está disponível
  3. read stdinvalue : leia stdin até EOL (ou EOF) e armazena a string em uma variável bash
  4. echo "$stdinvalue" : escreve o valor da variável stdinvalue como stdout

Espero que isso ajude.

    
por 07.05.2013 / 10:06