Diferenças nos espaços em branco entre o script bash e o shell interativo

2

Por favor, avise por que isso acontece.

de um shell bash do Linux:

ps
PID TTY          TIME CMD
20406 pts/0    00:00:01 bash
26896 pts/0    00:00:00 ps

Eu corro o seguinte

str="a b c d"
printf "%s\n"  ' echo $str '
a
b
c
d

mas do script bash

#!/bin/bash
.
.
.
.

str="a b c d"
printf "%s\n"  ' echo $str '

imprime:

a b c d  

enquanto os resultados esperados do script devem ser assim:

a
b
c
d

O que está faltando no meu script bash? Talvez o bash ENV, ou algo parecido?

Eu também corro o comando shopt do meu script bash e estes são os resultados:

  utocd  off
  cdable_vars  off
  cdspell  off
  checkhash  off
  checkjobs  off
  checkwinsize  off
  cmdhist  on
  compat31  off
  compat32  off
  compat40  off
  compat41  off
  direxpand  off
  dirspell  off
  dotglob  off
  execfail  off
  expand_aliases  off
  extdebug  off
  extglob  off
  extquote  on
  failglob  off
  force_fignore  on
  globstar  off
  gnu_errfmt  off
  histappend  off
  histreedit  off
  histverify  off
  hostcomplete  on
  huponexit  off
  interactive_comments  on
  lastpipe  off
  lithist  off
  login_shell  off
  mailwarn  off
  no_empty_cmd_completion  off
  nocaseglob  off
  nocasematch  off
  nullglob  off
  progcomp  on
  promptvars  on
  restricted_shell  off
  shift_verbose  off
  sourcepath  on
  xpg_echo  off
    
por yael 08.01.2018 / 18:43

1 resposta

4

Eu posso reproduzir esse comportamento apenas em dois casos:

  1. substituição de comando com aspas duplas:

    #!/bin/bash
    
    str="a b c d"
    printf "%s\n"  "'echo $str'"
    
  2. ou o Separador de campo interno alterado ( IFS variable), por exemplo:

    #!/bin/bash
    
    IFS=,
    str="a b c d"
    printf "%s\n" 'echo $str'
    

Em ambos os casos, a saída é

$ ./test.sh
a b c d

Para reparar o primeiro caso, apenas remova as aspas e, para restaurar IFS , configure-o para o valor padrão em algum lugar acima da substituição de comando.

IFS=$' \t\n'

Um pouco de explicação porque a saída é diferente quando IFS mudou e o que tem em comum com aspas duplas?

Vamos começar do final:

printf "%s\n" a b c d

é obviamente diferente de

printf "%s\n" 'a b c d'

No primeiro caso, temos quatro palavras separadas e printf envia-as uma a uma, adicionando uma nova linha a elas. No segundo caso, todo o a b c d é tratado como uma única palavra e printf apenas o envia como tal para o terminal. E agora deve ser óbvio que a saída de 'echo $str' é tratada como uma única palavra quando adicionalmente está entre aspas duplas.

Agora é onde IFS começa a desempenhar um papel. Ou seja, tt é usado para dividir palavras após as expansões, então com o padrão IFS=$' \t\n' a expressão echo a b c d outputs a b c d , mas com IFS=, ele se torna 'a b c d' - um único mundo, embora aspas não tenham sido usadas explicitamente. Pode-se verificar isso mais claramente sem variável:

$ IFS=,
$ printf "%s\n"  'echo a b c d'
a b c d

$ IFS=$' \t\n'
$ printf "%s\n"  'echo a b c d'
a
b
c
d

Como nota final: é melhor usar uma forma $() de substituição de comandos, não de backticks, mas esse é um tópico diferente.

    
por 08.01.2018 / 19:18