我注意到设置换行符IFS
应该以 $ 作为前缀
IFS=$'\n'
但如果设置一个冒号,就
IFS=:
是\n
一个变量吗?
答案1
这$'...'
不是bash
参数扩展,它是一种特殊的引用,它将ksh93
那些\n
, \x0a
,\12
代码扩展为换行符。zsh
还为具有相应 Unicode 代码点的字符添加了\u000a
/ 。并且也有一阵子了。还支持诸如.\U0000000a
ksh93
bash
\cj
zsh
\C-J
ksh93
\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 sh
。ksh93
并且bash
还有一种$"..."
用于文本本地化的引号形式,尽管它很少使用,因为部署和使用可移植且可靠很麻烦。
和es
shellfish
还可以使用\n
引号外部来扩展为换行符。
一些工具(例如 ) 、或 的printf
某些实现也可以自行扩展。例如,可以这样做:echo
awk
\n
printf '\n'
awk 'BEGIN{printf "\n"}'
echo
echo '\n\c' # UNIX compliant echos only
输出换行符,但请注意:
IFS=$(printf '\n')
不起作用,因为命令替换 ( $(...)
) 会删除所有尾随换行符。但是您可以使用:
eval "$(printf 'IFS="\n"')"
这是有效的,因为 的输出printf
以字符结尾"
,而不是换行符。
现在,为了完整性,在rc
shell 和导数(如es
或akanga
)中,$'\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
答案3
像这样的字符串$'\n'
已经由 POSIX 标准引入ksh93
,但目前还不是 POSIX 标准的一部分。
它们允许使用大多数与 C 类似的转义符,例如$'\u2345'
以及 也支持的转义符echo
。
请注意,如果您不喜欢(在 ksh93 或 bash 的情况下)使用该转义方法,您仍然可以使用:
IFS='
'
这是等效的,但更难阅读。
顺便说一句:这个扩展已经通过了 POSIX 标准委员会,但计划于SUSv8预计这种情况不会在 2020 年之前出现,因为我们首先需要解决落后于当前错误列表的问题。