bash中何时发生分词?

bash中何时发生分词?,bash,Bash,我过去认为他们非常理解bash脚本,但最近有一件事让我对我的理解产生了疑问: 我认为单词分割是通过分割扫描输入,然后用空格替换IFS值中的任何内容来实现的 我打印了我的IFS,它是 >>> echo “$IFS” | xxd 00000000: 2009 0a0a 这告诉我,需要将所有制表符、换行符和空格转换为空格 因此,决定对其进行测试: list_of_stuff=("\n") for elm in "${list_of_stuff[@]}" do echo $

我过去认为他们非常理解bash脚本,但最近有一件事让我对我的理解产生了疑问:

我认为单词分割是通过分割扫描输入,然后用空格替换
IFS
值中的任何内容来实现的

我打印了我的IFS,它是

>>> echo “$IFS” | xxd
00000000: 2009 0a0a
这告诉我,需要将所有制表符、换行符和空格转换为空格

因此,决定对其进行测试:

list_of_stuff=("\n")

for elm in "${list_of_stuff[@]}"
do
    echo $elm
done
我希望它将
\n
转换为
\s
。但是,当我运行此命令时,会得到以下输出:

>>> sh test_bash_script.sh


>>>

…这告诉我它并没有像我预期的那样将
\n
转换为
\s
。我应该在什么时候进行此转换?

您的数组中没有换行符,它有一个反斜杠字符,后跟一个“n”。当shell执行
echo$elm
时,它将
$elm
转换为“\n”,执行分词(未找到空白字符),并将其作为参数传递给
echo
echo
然后查看
\n
,并执行转义解释(有些版本的
echo
执行此操作,有些版本不执行此操作),将其转换为换行符并打印

使用'printf''%s'\n'$elm进行尝试,以更好地了解正在发生的情况:

$ list_of_stuff=("\n")
$ for elm in "${list_of_stuff[@]}"; do
> printf "'%s'\n" $elm
> done
'\n'
$ list2=($'\n')    # This'll give an actual newline
$ for elm in "${list2[@]}"; do
> printf "'%s'\n" $elm
> done
''
但是。。。为什么第二次什么也没印?这是因为
$elm
扩展为一个新行,将单词拆分为0个单词,因此它运行了与
printf“'%s'\n”
等效的程序,只打印两个单引号,后跟一个新行

顺便说一句,您还可以使用
set-x
更好地了解这种情况下的情况。在最初的情况下,它将显示它正在执行与
echo'\n'
等效的操作

[编辑]回答有关“已转换为0个单词”和等效于
printf“'%s'\n”
的问题:分词不会将任何内容转换为空格;它将字符串转换为一系列单词。如果
echo
获取多个参数(“单词”),它会将它们粘在一起,并在它们之间加上空格,因此单词分割+
echo
可以将所有空格转换为单个空格,但实际上单词分割本身并不是这样做的。考虑几个例子:

$ var1=$' \t word1 \n  \t  word2   \nword3 \n \n '    # Note that $' ' converts escape sequences
$ printf "'%s'\n" "$var1"    # This prints the actual contents with quotes around, no further interpretation
'    word1 
      word2   
word3 


'
$ echo $var1    # No quotes, so it gets word-split; echo pastes together with spaces
word1 word2 word3
$ printargs() {    # Let's define a function to show what's happening more clearly
> echo "Received $# arguments:"
> for arg in "$@"; do
> printf "   '%s'\n" "$arg"
> done
> }
$ printargs $var1
Received 3 arguments:
   'word1'
   'word2'
   'word3'
$ var2=$' \t \t    \n \t   '    # All whitespace this time
$ printf "'%s'\n" "$var2"
'           
       '
$ echo $var2

$ printargs $var2
Received 0 arguments:
让我们更详细地了解一下
echo
printargs
命令。在
echo$var1
中,
$var1
的值在空格(空格、制表符和换行符)上进行单词拆分,将其转换为三个单词:“word1”、“word2”和“word3”。这里没有空间,它们都被移除了。因此,它执行相当于
echo“word1”、“word2”和“word3”
echo
接受这三个参数,在它们之间添加空格,并打印结果

现在,我将
printargs
定义为一个函数,用于打印它得到的参数数量,后跟每个参数(缩进和单引号)。因此,在
printargs$var1
中,单词拆分也会发生同样的情况,因此它执行与
printargs“word1”“word2”“word3”等价的
,因此
printargs
报告它有三个参数,并分别打印每个参数(没有空格,除了我为缩进添加的空格)

好的,接下来的一系列示例:

$ var1=$' \t word1 \n  \t  word2   \nword3 \n \n '    # Note that $' ' converts escape sequences
$ printf "'%s'\n" "$var1"    # This prints the actual contents with quotes around, no further interpretation
'    word1 
      word2   
word3 


'
$ echo $var1    # No quotes, so it gets word-split; echo pastes together with spaces
word1 word2 word3
$ printargs() {    # Let's define a function to show what's happening more clearly
> echo "Received $# arguments:"
> for arg in "$@"; do
> printf "   '%s'\n" "$arg"
> done
> }
$ printargs $var1
Received 3 arguments:
   'word1'
   'word2'
   'word3'
$ var2=$' \t \t    \n \t   '    # All whitespace this time
$ printf "'%s'\n" "$var2"
'           
       '
$ echo $var2

$ printargs $var2
Received 0 arguments:
再一次,让我们更详细地看一下最后两个命令:在
echo$var2
中,单词拆分在
$var
的值中找到零个单词——都是空白——因此它将零个参数传递给
echo
。该命令仅相当于
echo
,完全没有参数。因此,
echo
只打印一个空行(没有空格或任何内容)。类似地,在
printf“'%s'\n”$var2
中,
$var2
字拆分为零字,因此
printargs
获取(并报告获取)零参数。将输出与这些完全等效的命令进行比较:

$ echo

$ printargs
Received 0 arguments:

数组中没有换行符,它有一个反斜杠字符后跟一个“n”。当shell执行
echo$elm
时,它将
$elm
转换为“\n”,执行分词(未找到空白字符),并将其作为参数传递给
echo
echo
然后查看
\n
,并执行转义解释(有些版本的
echo
执行此操作,有些版本不执行此操作),将其转换为换行符并打印

使用'printf''%s'\n'$elm进行尝试,以更好地了解正在发生的情况:

$ list_of_stuff=("\n")
$ for elm in "${list_of_stuff[@]}"; do
> printf "'%s'\n" $elm
> done
'\n'
$ list2=($'\n')    # This'll give an actual newline
$ for elm in "${list2[@]}"; do
> printf "'%s'\n" $elm
> done
''
但是。。。为什么第二次什么也没印?这是因为
$elm
扩展为一个新行,将单词拆分为0个单词,因此它运行了与
printf“'%s'\n”
等效的程序,只打印两个单引号,后跟一个新行

顺便说一句,您还可以使用
set-x
更好地了解这种情况下的情况。在最初的情况下,它将显示它正在执行与
echo'\n'
等效的操作

[编辑]回答有关“已转换为0个单词”和等效于
printf“'%s'\n”
的问题:分词不会将任何内容转换为空格;它将字符串转换为一系列单词。如果
echo
获取多个参数(“单词”),它会将它们粘在一起,并在它们之间加上空格,因此单词分割+
echo
可以将所有空格转换为单个空格,但实际上单词分割本身并不是这样做的。考虑几个例子:

$ var1=$' \t word1 \n  \t  word2   \nword3 \n \n '    # Note that $' ' converts escape sequences
$ printf "'%s'\n" "$var1"    # This prints the actual contents with quotes around, no further interpretation
'    word1 
      word2   
word3 


'
$ echo $var1    # No quotes, so it gets word-split; echo pastes together with spaces
word1 word2 word3
$ printargs() {    # Let's define a function to show what's happening more clearly
> echo "Received $# arguments:"
> for arg in "$@"; do
> printf "   '%s'\n" "$arg"
> done
> }
$ printargs $var1
Received 3 arguments:
   'word1'
   'word2'
   'word3'
$ var2=$' \t \t    \n \t   '    # All whitespace this time
$ printf "'%s'\n" "$var2"
'           
       '
$ echo $var2

$ printargs $var2
Received 0 arguments:
让我们更详细地了解一下
echo
printargs
命令。在
echo$var1
中,
$var1
的值在空格(空格、制表符和换行符)上进行单词拆分,将其转换为三个单词:“word1”、“word2”和“word3”。这里没有空间,它们都被移除了。因此,它执行与echo“word1”word2“word3”等价的
echo
,接受这三个参数,在它们之间添加空格,并打印结果