Faz enquanto desova um subshell no bash? [duplicado]

12

Alguém pode explicar por que esse script não produz a saída que eu esperava?

 #!/bin/bash
 #

var=0

ls -1 /tmp| while read file
do
     echo $file
     var=1
done

echo "var is $var"

Eu recebo uma lista de arquivos seguidos por var is 0

Por que o var não é igual a 1? É porque o loop while gera um sub-shell?

    
por Aditya K 20.05.2015 / 16:01

3 respostas

11

A tubulação faz. Você pode verificar por si mesmo, por exemplo, imprimindo $BASHPID dentro e fora do loop while ou fazendo algo como:

ls | while read file; do
    sleep 100;
done

, parando com C-Z e verificando ps ou ps --forest depois para ver a árvore de processos em sua sessão de terminal.

Você pode evitar o subshell "piping" de maneira um pouco diferente:

var=0
while read file
do 
  echo $file; var=1
done < <(ls -1 /tmp/)

echo $var #=> 1
    
por 20.05.2015 / 16:14
5

O motivo pelo qual seu valor variável não é mantido já foi explicado pela outra boa resposta. Se você quiser, pode ler um artigo interessante sobre esse assunto em Eu defino variáveis em um loop que está em um pipeline. Por que eles desaparecem depois que o loop termina? Ou, por que não posso enviar dados para ler? .

Eu só quero mostrar outra maneira de percorrer seus arquivos, para que você não analise ls :

for file in /tmp/*
do
   echo "$file"
   var=1
done

É isso! Apenas deixe /tmp/* expandir para fornecer todo o conteúdo no diretório /tmp .

Eu acho que seu script era apenas um código falso, não o código real. Mas se você estiver checando se /tmp contém alguns valores ou não, você também pode dizer:

shopt -s nullglob
r=(/tmp/*)

Em seguida, conte os elementos na matriz:

echo ${#r[@]}

Observe que usei shopt -s nullblog para impedir que /tmp/* se expandisse para a string literal /tmp/* se nada corresponder a esse padrão.

    
por 20.05.2015 / 17:32
1

while não, mas um pipe faz, então o while no seu exemplo será executado em um subshell por causa disso

Geralmente, é possível realizar a mesma tarefa com um loop for , no qual o comando que produz a lista para iterar é executado na sub-camada, em vez do loop. Por exemplo:

for file in /tmp/*; do
    echo "$file"
    var=1
done
    
por 20.05.2015 / 16:02

Tags