请告知为什么会发生这种情况。
从 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
我只能在两种情况下重现此行为:
双引号命令替换:
#!/bin/bash str="a b c d" printf "%s\n" "`echo $str`"
或更改内部字段分隔符(
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
最后一点:最好使用$()
命令替换形式,而不是反引号,但这是不同的主题。