IFS = $'\ n'的确切含义是什么?


123

如果是以下示例,该示例将IFS环境变量设置为换行字符...

IFS=$'\n'
  • 什么是美元符号的意思 完全相同
  • 在这种特定情况下该怎么办?
  • 在哪里可以找到有关此特定用法的更多信息(Google不允许在搜索中使用特殊字符,否则我不知道该怎么找)?

我知道什么是IFS环境变量,什么是\n字符(换行符),但是为什么不只使用以下形式:( IFS="\n"不起作用)?

例如,如果我想遍历文件的每一行并想使用for循环,则可以这样做:

for line in (< /path/to/file); do
    echo "Line: $line"
done

但是,除非IFS将其设置为换行符,否则此方法将无法正常工作。为了使其正常工作,我必须这样做:

OLDIFS=$IFS
IFS=$'\n'
for line in (< /path/to/file); do
    echo "Line: $line"
done
IFS=$OLDIFS

注意:我不需要另一种方法来做同样的事情,我已经知道很多其他事情了……我只是很好奇,$'\n'想知道是否有人可以给我一个解释。

Answers:


161

通常bash不会在字符串文字中解释转义序列。因此,如果您编写\n"\n"'\n',则不是换行符-它是字母n(在第一种情况下)或反斜杠后跟字母n(在其他两种情况下)。

$'somestring'带有转义序列的字符串文字语法。所以不像'\n'$'\n'实际上是一个换行符。


2
并非完全如此- \n只是一个(转义的)字母n。你是正确的,'\n'并且"\n"是反弹后跟n。
Roman Cheplyaka

15
请注意,这$'\n'是特定于bash的-在POSIX shell(/bin/sh)中不起作用。要以兼容POSIX的方式获得相同的效果,您可以键入IFS=',然后按回车键以键入实际的换行符,然后键入结束符'
Richard Hansen

23
IFS=$(echo -e '\n')还应该以POSIX兼容的方式进行。
Vineet

12
@Vineet-让我停下来对已发表的评论提出异议。尽管这 Posix正确的,但是它不起作用-bash中的命令替换运算符将删除所有结尾的换行符。有关更多详细信息,请参见此内容
Digital Trauma

9
@DigitalTrauma我认为它甚至都不是POSIX:-e未定义,并且\n没有-e作为XSI扩展起作用pubs.opengroup.org/onlinepubs/9699919799/utilities/…printf '\n'岩石;)
西罗Santilli郝海东冠状病六四事件法轮功

20

只是给该结构起其正式名称:形式的字符串$'...'称为ANSI C引用的字符串

也就是说,与[ANSI] C字符串一样,可以识别反冲转义序列并将其扩展为它们的字面等效项(有关支持的转义序列的完整列表,请参见下文)。

之后这种扩张,$'...'行为相同的方式为字符串'...'字符串 -也就是说,它们会被视为文字不受任何[其它] shell扩展

例如,$'\n'扩展为文字换行符-这是常规bash字符串文字(无论是'...'还是"...")都无法做到的。[1]

另一个有趣的功能是ANSI C引号的字符串可以转义'(单引号)为\',而'...'(常规单引号字符串)则不能:

echo $'Honey, I\'m home' # OK; this cannot be done with '...'

支持的转义序列列表

反斜杠转义序列(如果存在)的解码方式如下:

\警报(响铃)

\ b退格键

\ e \ E转义字符(不是ANSI C)

\ f换页

\ n换行符

\ r回车

\ t水平制表符

\ v垂直标签

\反斜杠

\'单引号

\“双引号

\ nnn八位字符,其值为八进制值nnn(一到三位数字)

\ xHH八位字符,其值是十六进制值HH(一个或两个十六进制数字)

\ uHHHH Unicode(ISO / IEC 10646)字符,其值为十六进制值HHHH(一到四个十六进制数字)

\ UHHHHHHHH为Unicode(ISO / IEC 10646)字符,其值为十六进制值HHHHHHHH(1至8个十六进制数字)

\ cx一个control-x字符

扩展结果是单引号,好像没有美元符号。


[1]但是,您可以在'...'和“ ...”字符串中嵌入实际的换行符;即,您可以定义跨越多行的字符串。



8

重新恢复默认的IFS,这OLDIFS=$IFS是没有必要的。在子shell中运行新的IFS,以避免覆盖默认的IFS:

ar=(123 321); ( IFS=$'\n'; echo ${ar[*]} )

此外,我真的不相信您会完全恢复旧的IFS。您应该用双引号将其括起来,以免出现断行现象OLDIFS="$IFS"


2
这是一个非常有用的技术。我只是用它来清洁外壳加入OP: args=$(IFS='&'; echo "$*")IFS$' \t\n'Bourne shell友好的方式恢复,绝非易事。
jeberle 2014年

回复Besides I don't really believe you recover the old IFS fully:是分词没有对变量赋值的RHS执行(但报价去除),所以OLDIFS=$IFSOLDIFS="$IFS"行为方式相同。
mklement0

3

ANSI C引号的字符串是关键点。感谢@ mklement0。

您可以使用命令od测试ANSI C引用的字符串。

echo -n $'\n' | od -c
echo -n '\n' | od -c
echo -n $"\n" | od -c
echo -n "\n" | od -c

输出:

0000000  \n  
0000001

0000000   \   n   
0000002

0000000   \   n   
0000002

0000000   \   n   
0000002

您可以通过输出清楚地了解含义。


-7

就像从变量中获取值一样:

VAR='test'
echo VAR
echo $VAR

是不同的,因此美元符号基本上可以评估内容。


6
这与变量无关。$'FOO'(与$FOO该问题无关)(是与之无关的)是字符串文字。如果执行echo $'VAR',将看到它输出的VAR不是字符串test
sepp2k 2010年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.