在 Bash 中,分词是命令行处理中的一个步骤。来自 Bash 手册
shell 将 $IFS 的每个字符视为分隔符,并使用这些字符作为字段终止符将其他扩展的结果拆分为单词。如果 IFS 未设置,或其值恰好是
<space><tab><newline>
默认值,则<space>, <tab>, and <newline>
忽略先前扩展结果的开头和结尾处的序列,并且不在开头或结尾处的任何 IFS 字符序列用于分隔单词。如果 IFS 具有默认值以外的值,则只要空白字符位于 IFS 值(IFS 空白字符)中,单词开头和结尾的空白字符 space 和 tab 序列就会被忽略。 IFS 中非 IFS 空白的任何字符以及任何相邻的 IFS 空白字符共同界定字段。 IFS 空白字符序列也被视为分隔符。如果IFS的值为空,则不会发生分词。
我想重写以下示例,以便space
将参数a
, b
and之间的分隔符c
替换为tab
ornewline
$ echo a b c
a b c
但当我按下按键时Tab
,却没有任何反应。
当我点击\
和时,输出中的、和return
之间没有空格:a
b
c
$ echo a\
> b\
> c
abc
为什么我不能按照引文所说的去做?
顺便说一句,没有任何结果$IFS
:
$ echo $IFS
答案1
换行符由 特殊处理bash
,无论 的值如何IFS
。换行符前的反斜杠会导致换行符被忽略。与分词无关,即使IFS
设置为某个自定义值也会发生。
从LESS=+/^QUOTING man bash
:
A non-quoted backslash (\) is the escape character. It preserves the literal value of the next character that follows, with the exception of <newline>. If a \<newline> pair appears, and the backslash is not itself quoted, the \<newline> is treated as a line continuation (that is, it is removed from the input stream and effectively ignored).
您可以看到换行符上的单词分割以另一种方式发生:将换行符填充到变量中,然后echo
在不引用它的情况下对该变量进行引用。
$ myvar=a$'\n'b$'\n'c
$ echo "$myvar"
a
b
c
$ echo $myvar
a b c
$
答案2
直接回答
这未引用的命令:echo a b c
,将在(元字符空间)上分割,无论IFS
是什么或不是。echo
: 的split 参数将用空格打印a
,因为 echo 定义如下:b
c
LESS=+/'^ *echo \[-neE\] \[arg ...\]' man bash
输出参数,用空格分隔,后跟换行符。
亦无$IFS
参与。
所以,你引用的内容在这里没有相关性。关键部分是:
...将其他扩展的结果拆分为单词...
你必须$IFS
使用之前有一个扩展。
中没有任何扩展a b c
。
如果必须使用 $IFS 的效果,请使用不带引号的扩展:
$ var='a b c'
$ echo $var
a b c
但这仍然不$IFS
用于输出,仅用于分割。
输出中的 IFS。
哪里$IFS
有相关性(对于输出)在$*
.
$ set -- a b c
$ IFS=$'\t'
$ printf '%s\n' "$*" | od -An -vtx1c
61 09 62 09 63 0a
a \t b \t c \n
这是你所需要的吗?
其他事宜。
键盘选项卡
当我按下Tab键时,没有任何反应
然后同时按下CtrlV,松开,然后按下Tab。
但如果没有引号,您将无法将制表符分配给变量。测试:
$ var=a b ### The space represents a tab as above.
bash: b: command not found
你会需要:
$ var="a b" ### The space represents a tab as above.
至少双引号。
报价 IFS
$IFS 没有任何结果:
$ echo $IFS
$IFS
因为你没有引用,所以什么也没有产生$IFS
。尝试:
<user>$ echo "$IFS" | sed -n l
\t$
$
<user>$
其中有一个来自命令 echo 的新行$IFS
和一个来自命令 echo 的新行。
更好地更改为 printf:
<user>$ printf '%s' "$IFS" | sed -n l
\t$
<user>$
并使用 od:
$ printf '%s' "$IFS" | od -An -vtx1c
20 09 0a
\t \n
因为我们已经有一种方法可以“查看”字符串中包含哪些字符。
我们也可以用它来“查看”几个字符串内的内容:
$ var='a b c'
$ echo "$var" | od -An -vtx1c
61 20 62 20 63 0a
a b c \n
这不足为奇。因为这(带单引号)不应该是:
$ var='a\
> b\
> c'
$ echo "$var" | od -An -vtx1c
61 5c 0a 62 5c 0a 63 0a
a \ \n b \ \n c \n
正是键入的内容。如果正确引用了 var,反斜杠就会正确显示。
引用
但用双引号引用可能会改变一些字符:
$ var="a\
> b\
> c"
$ echo "$var" | od -An -vtx1c
61 62 63 0a
a b c \n
但是您所写的内容没有关于设置 var 或在 echo 上使用它的引号。
这在 shell 中是一条禁忌规则。请正确引用。
答案3
要将空格替换为制表符,$IFS
可以使用参数数组:
unset IFS
set a b c
IFS=$(printf \\t)
printf "%s\n" "$*"
了解这$IFS
与拆分有关 - 它包含 shell 用于拆分列表上下文中未加引号的扩展的字符列表。你不能真正用它来代替特殊 shell 参数的特殊情况除外的字符$*
。在所有其他情况下,其使用将相当于无效的明确和界定未引用的 shell 扩展的某些部分。