bash 脚本和交互式 shell 之间空格的差异

bash 脚本和交互式 shell 之间空格的差异

请告知为什么会发生这种情况。

从 Linux bash shell:

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

我运行以下命令

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

但来自 bash 脚本

#!/bin/bash
.
.
.
.

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

它打印:

a b c d  

而脚本的预期结果应该是这样的:

a
b
c
d

我的 bash 脚本中缺少什么?也许是 bash ENV,或者类似的东西?

我还shopt从 bash 脚本运行命令,结果如下:

  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

答案1

我只能在两种情况下重现此行为:

  1. 双引号命令替换:

    #!/bin/bash
    
    str="a b c d"
    printf "%s\n"  "`echo $str`"
    
  2. 或更改内部字段分隔符(IFS变量),例如:

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

在这两种情况下输出都是

$ ./test.sh
a b c d

要修复第一种情况,只需删除引号,而要恢复,IFS只需将其设置为命令替换上方某处的默认值即可。

IFS=$' \t\n'

稍微解释一下为什么IFS更改后输出会有所不同,以及它与双引号有什么共同点?

让我们从最后开始:

printf "%s\n" a b c d

明显不同于

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

在第一种情况下,我们有四个单独的单词,并printf逐个输出它们,并向它们添加新行。在第二种情况下,整个单词a b c d被视为单个单词,并printf直接将其输出到终端。现在应该很明显,当另外加双引号时, 的输出`echo $str`被视为单个单词。

现在是IFS开始发挥作用的地方。也就是说, tt 用于在扩展后分割单词,因此默认情况下IFS=$' \t\n'表达式echo a b c d输出a b c d,但IFS=,它变成了'a b c d'- 一个世界,尽管没有明确使用引号。人们可以在没有变量的情况下更清楚地检查这一点:

$ 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

最后一点:最好使用$()命令替换形式,而不是反引号,但这是不同的主题。

相关内容