我在阅读有关IFS的博客时看到了这一行:
for i in $(<test.txt)
并认为$(<test.txt)
将文件内容打印到STDOUT。我可能在此方面做错了,但是出于好奇,我尝试在Shell上执行此操作。因此,选择了一个名为array
随机数据的随机文件,
首先做了一个cat array
给我的东西:
amit@C0deDaedalus:~/test$
amit@C0deDaedalus:~/test$ cat array
1) Ottawa Canada 345644
2) Kabul Afghanistan 667345
3) Paris France 214423
4) Moscow Russia 128793
5) Delhi India 142894
然后这样做$(<array)
给了我这个:
amit@C0deDaedalus:~/test$ $(<array)
1) Ottawa Ca: command not found
我只知道它<
用于输入重定向,但不能完全得到shell解释为命令的内容。
谁能解释这个怪异的输出在shell背后的概念?
更新 :-
在运行时,set -x
它给出了以下内容:
amit@C0deDaedalus:~/test$ $(<array)
+ '1)' Ottawa Canada 345644 '2)' Kabul Afghanistan 667345 '3)' Paris France 214423 '4)' Moscow Russia 128793 '5)' Delhi India 142894
+ '[' -x /usr/lib/command-not-found ']'
+ /usr/lib/command-not-found -- '1)'
1): command not found
+ return 127
amit@C0deDaedalus:~/test$
该$(command)
语法command
在subshell环境中执行,并将其自身替换为的标准输出command
。而且,正如Bash Manual所说,$(< file)
只是速度更快$(cat file)
(不过,这不是POSIX功能)。
因此,当您运行时$(<array)
,Bash执行该替换,然后它将第一个字段用作命令的名称,并将其余字段用作命令的参数:
$ $(<array)
1): command not found
我没有任何1)
命令/功能,因此它会显示一条错误消息。
但是在您的特定情况下,您可能会收到另一条错误消息,原因可能是您修改了IFS变量:
$ IFS=n; $(<array)
1) Ottawa Ca: command not found
我的猜测是您IFS
被修改了,所以这就是您的shell尝试执行1) Ottawa Ca
而不是的原因1)
。毕竟,您正在阅读IFS
相关文章。如果您IFS
最终获得一个怪异的价值,我不会感到惊讶。
该IFS
变量控制所谓的单词拆分或字段拆分。它基本上定义了Shell在扩展上下文中(或其他命令,如read
)如何解析数据。
3.5.7分词
Shell扫描参数扩展,命令替换和算术扩展的结果,这些结果在双引号中没有出现,以进行词拆分。
外壳程序将的每个字符
$IFS
视为定界符,并使用这些字符作为字段终止符将其他扩展的结果拆分为单词。如果IFS
没有设置,或者它的值是完全<space><tab><newline>
,默认值,然后序列<space>
,<tab>
以及<newline>
在开始和以前扩张的结果最终会被忽略,而任何序列IFS
在开始时没有字符或结束用于分隔单词。如果IFS
具有默认值以外的其他值,则在单词的开头和结尾都将忽略空格字符space
,,tab
和的序列newline
,只要空格字符位于IFS
(IFS
空格字符)的值中即可。其中的任何字符IFS
都不是IFS
空格以及任何相邻的IFS
空格字符分隔一个字段。IFS
空格字符序列也被视为定界符。如果的值为IFS
null,则不会发生词拆分。显式的空参数(
""
或''
)将保留并作为空字符串传递给命令。删除因无值的参数扩展而导致的无引号的隐式空参数。如果将没有值的参数用双引号引起来,则会生成空参数并将其保留并作为空字符串传递给命令。当带引号的空参数作为扩展为非空的单词的一部分出现时,空参数将被删除。也就是说,单词在拆分单词和删除空参数之后-d''
成为-d
单词。请注意,如果不发生扩展,则不会执行拆分。
以下是有关IFS
和命令替换用法的一些示例:
范例1:
$ IFS=$' \t\n'; var='hello world'; printf '[%s]\n' ${var}
[hello]
[world]
$ IFS=$' \t\n'; var='hello world'; printf '[%s]\n' "${var}"
[hello world]
在这两种情况下,IFS
is <space><tab><newline>
(默认值),var
ishello world
和都有一条printf
语句。但是请注意,在第一种情况下执行单词拆分,而在第二种情况下则不执行(因为双引号禁止该行为)。单词拆分发生在不带引号的扩展中。
范例2:
$ IFS='x'; var='fooxbar'; printf '[%s]\n' ${var}
[foo]
[bar]
$ IFS='2'; (exit 123); printf '[%s]\n' ${?}
[1]
[3]
既不包含空格${var}
也不${?}
包含任何空格,因此人们可能会认为在这种情况下分词不会成为问题。但这不是事实,因为它IFS
可能会被滥用。IFS
几乎可以拥有任何价值,而且很容易滥用。
范例3:
$ $(echo uname)
Linux
$ $(xxd -p -r <<< 64617465202d75)
Sat Apr 28 12:46:49 UTC 2018
$ var='echo foo; echo bar'; eval "$(echo "${var}")"
foo
bar
这与分词无关,但请注意我们如何使用一些肮脏的技巧来注入代码。
相关问题:
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句