Bash

bash 腳本和互動式 shell 之間的空格差異

  • January 8, 2018

請告知為什麼會發生這種情況。

來自 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`"
  1. 或更改內部欄位分隔符(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

最後一點:最好使用一種$()命令替換形式,而不是反引號,但這是不同的主題。

引用自:https://unix.stackexchange.com/questions/415631