什么时候在bash中发生分词?

时间:2017-09-20 05:04:42

标签: bash

我曾经认为很好地理解了bash脚本,但最近有些事情让我的理解受到质疑:

我认为单词拆分的工作原理是拆分扫描输入,然后用空格替换IFS的值中的任何内容。

我打印了我的IFS,它是

>>> echo “$IFS” | xxd
00000000: 2009 0a0a

告诉我应该将所有制表符,换行符和空格转换为JUST空格。

所以,决定测试一下:

list_of_stuff=("\n")

for elm in "${list_of_stuff[@]}"
do
    echo $elm
done

我希望它会将\n转换为\s。但是,当我运行它时,得到以下输出:

>>> sh test_bash_script.sh


>>>

..它告诉我它没有按照我的预期将\n转换为\s。我什么时候应该期待这种转换?

1 个答案:

答案 0 :(得分:2)

你的数组中没有换行符,它有一个反斜杠字符后跟一个“n”。当shell执行echo $elm时,它会将$elm转换为'\ n',执行分词(找不到空白字符),并将其作为参数传递给echoecho然后会看到\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'

让我们更详细地看一下echoprintargs命令。在echo $var1中,$var1的值在空格(空格,制表符和换行符)上进行分词,将其转换为三个词:“word1”,“word2”和“word3”。这里没有空格,它们都被删除了。所以它执行相当于echo "word1" "word2" "word3"echo获取这三个参数,在它们之间添加空格,并打印结果。

现在,我将printargs定义为一个函数,用于打印它获得的参数数量,后跟每个参数(缩进和单引号)。所以在printargs $var1中,单词分裂发生的相同,所以它执行相当于printargs "word1" "word2" "word3",因此printargs报告它有三个参数,并分别打印每个参数(没有空格,除了那些我为缩进添加的内容。)

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

$ 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: