A saída da variável de loop mostra um valor diferente do esperado

A saída da variável de loop mostra um valor diferente do esperado

Imagine que tenho duas pastas no meu diretório de trabalho atual: back/e front/. Estou tentando entrar em cada um deles e fazer algumas coisas. Do script simples abaixo:

for dir in */ ; do
    echo "$(dir)"
done

Eu estava esperando uma saída como:

back
front

No entanto, o que estou recebendo é:

back  front
back  front

Eu não entendo. A consequência é que, se eu tentar cdentrar na pasta:

for dir in */ ; do
    echo "$(dir)"
    cd $(dir)
    echo "$(pwd)"
    cd ..
done

Eu recebo:

back  front
/path/to/back
back  front
/path/to/back

Ou seja, eu nunca entro front/. Alguém poderia me ajudar a entender o que estou fazendo de errado?

Responder1

Em shells do tipo POSIX, $(cmd)a sintaxe parasubstituição de comando, $(cmd)é expandido para a saída cmdmenos os caracteres de nova linha finais.

O que você quer em vez disso éexpansão de parâmetros: $dirou ${dir}(aqui com o parâmetro sendo odir variável).

pwd( print working directory) é o comando que gera o conteúdo da $PWD¹ variável especial que contém um caminho para o diretório de trabalho atual, portanto, $(pwd)expande para a mesma coisa, $PWDdesde que $PWDnão termine em caracteres de nova linha.

Então você quer:

for dir in */; do 
  (
    printf '%s\n' "$dir"
    cd -- "$dir" &&
      printf '%s\n' "$PWD"
  )
done

Ou:

for dir in */; do 
  (
    printf '%s\n' "$dir"
    cd -- "$dir" &&
      pwd
  )
done

Lembre-se também disso

  • echonão pode ser usado para gerar dados arbitrários, use printfem vez disso
  • geralmente você deve verificar o status de saída dos comandos. Aqui, não verificar a saída de cdsignificaria que o seguinte cd ..o levaria ao lugar errado se o primeiro cdfalhasse.
  • é melhor executar cdem um subshell (usando (...)) em vez de usar cd .., pois o último nem sempre garante que você retorne ao local inicial (se houver links simbólicos envolvidos e/ou alguns componentes do caminho tiverem sido renomeados no intervalo)
  • --deve ser usado para separar opções de não opções quando não é possível garantir que as não opções não comecem -(ou +o que também pode ser um problema para alguns comandos).
  • em shells do tipo POSIX, expansões de parâmetros e substituições de comandos (e expansões aritméticas) devem ser citadas, caso contrário, elas passam por divisão + glob implícita (exceto em zsh), o que você geralmente não deseja.

Lembre-se também de que no bash (e em outros shells POSIX, exceto zsh), quando um glob não corresponde a nenhum arquivo, ele não é expandido.

Portanto, se o diretório de trabalho atual não contiver nenhum arquivo não oculto que possa ser determinado como sendo do tipodiretório, o */padrão glob irá apenas se expandir para si mesmo */em vez de uma lista vazia e você provavelmente verá um erro informando cdque ele não pode entrar nesse */diretório.

Em zsh, você usaria o Nqualificador glob como em for dir in */(N); do...(ou for dir in *(N-/); do...para evitar $dirterminar em /).

Em ksh93 for dir in ~(N)*/; do...:.

Em bash, você pode definir a nullglobopção globalmente temporariamente:

shopt -s nullglob
for dir in */; do
  ...
done
shopt -u nullglob

Para completar, $(var)a sintaxe paramacroexpansões em Makefiles conforme usado pelo makecomando.

Na awklinguagem, $é um operador unário para desreferenciar campos, e você usa apenas varpara se referir a uma awkvariável. Então, $(var)seria o mesmo que $varou $ vare expandiria para o varcampo (ou todo o registro se varfor 0).

Em rcshells semelhantes a -, $(var)o mesmo que $var, $ var, $ 'var', $ ( 'var' )também funcionaria, já que é uma lista de um elemento passado para $, então você está desreferenciando a varvariável, embora normalmente usaria apenas $var.

No TCL, $(var)expandiria para o valor da variável array com nome vazio para a varchave:

$ tclsh
% array set {} {foo 1 bar 2}
% puts $(foo)
1

¹ Sim, Ppara Print não faz muito sentido neste contexto. Como você pode imaginar, o pwdcomando (do Unix V5 em meados dos anos 70) foi o primeiro, e $PWDológicoo manuseio do diretório de trabalho atual, ambos especificados pelo POSIX, veio mais tarde (em ksh no início dos anos 80, onde pwdna verdade era um alias para print - $PWD(sim, com as faltas -re aspas!) E $PWDfoi bracronizado com o bracronyd Present Working Directory na documentação). tcshtem uma variável $cwd( current working directory) para o mesmo propósito

informação relacionada