`IFS=$'\n' 中的 '\n' 是变量吗?

`IFS=$'\n' 中的 '\n' 是变量吗?

我注意到设置换行符IFS应该以 $ 作为前缀

IFS=$'\n'

但如果设置一个冒号,就

IFS=:

\n一个变量吗?

答案1

$'...'不是bash参数扩展,它是一种特殊的引用,它将ksh93那些\n, \x0a,\12代码扩展为换行符。zsh还为具有相应 Unicode 代码点的字符添加了\u000a/ 。并且也有一阵子了。还支持诸如.\U0000000aksh93bash\cjzsh\C-Jksh93\x{a}

$是一个暗示,它是某种形式或扩展。但无论如何,它与使用$(如$((1 + 1))$param$(cmd))的其他形式的扩展不同,因为它不在双引号或此处文档内执行(在所有 shell 中echo "$'x'"输出$'x',尽管每个 POSIX 未指定),并且它的扩展不受分割+glob,它绝对更接近于引用运算符而不是扩展运算符。

IFS=\n会将 IFS 设置为n\被视为引用运算符),IFS="\n"或者IFS='\n'会将 IFS 设置为两个字符反斜杠和n

您还可以使用:

IFS='
'

或者

IFS="
"

或者

IFS=$'
'

set list要传递文字换行符,尽管这不太清晰(除了使用诸如该代码中vi是否包含其他空格字符之类的东西之外,人们看不到其他内容)。$IFS

IFS=:IFS=':'IFS=":"IFS=$':'全部将 IFS 设置为,:因此使用哪个都无关紧要。

$'...'至少受以下支持(有变体):ksh93, zsh, bash, mksh, busybox sh, FreeBSD shksh93并且bash还有一种$"..."用于文本本地化的引号形式,尽管它很少使用,因为部署和使用可移植且可靠很麻烦。

esshellfish还可以使用\n引号外部来扩展为换行符。

一些工具(例如 ) 、或 的printf某些实现也可以自行扩展。例如,可以这样做:echoawk\n

printf '\n'
awk 'BEGIN{printf "\n"}'
echo
echo '\n\c' # UNIX compliant echos only

输出换行符,但请注意:

IFS=$(printf '\n')

不起作用,因为命令替换 ( $(...)) 会删除所有尾随换行符。但是您可以使用:

eval "$(printf 'IFS="\n"')"

这是有效的,因为 的输出printf以字符结尾",而不是换行符。

现在,为了完整性,在rcshell 和导数(如esakanga)中,$'\n'确实是该变量的扩展(名称是两个字符和\n的序列的变量)。这些 shell 对变量名称可以包含的字符没有限制,并且只有一种类型的引号:。\n'...'

$ rc
; '\n' = (foo bar)
; echo $'\n'
foo bar
; echo $'\n'(1)
foo

rc变量也全部导出到环境中,但至少在 的 Unix 变体中rc,对于像 这样的变量名称\n,环境变量版本会经过某种形式的编码:

; env | grep foo | sed -n l
__5cn=foo\001bar$

0x5c是 ASCII 的字节值\;另请参阅如何使用 0x1 字节作为分隔符对该数组变量进行编码)。

答案2

这是ANSI-C 引用:

该形式的单词$'string'经过特殊处理。该单词扩展为string,并按照 ANSI C 标准指定的方式替换反斜杠转义字符。

因此$'\n'被换行符替换。

这与以下无关shell参数扩展,尽管使用$.

答案3

像这样的字符串$'\n'已经由 POSIX 标准引入ksh93,但目前还不是 POSIX 标准的一部分。

它们允许使用大多数与 C 类似的转义符,例如$'\u2345'以及 也支持的转义符echo

请注意,如果您不喜欢(在 ksh93 或 bash 的情况下)使用该转义方法,您仍然可以使用:

IFS='
'

这是等效的,但更难阅读。

顺便说一句:这个扩展已经通过了 POSIX 标准委员会,但计划于SUSv8预计这种情况不会在 2020 年之前出现,因为我们首先需要解决落后于当前错误列表的问题。

相关内容