为什么变量赋值会在 shell 中用空格替换制表符?
$ cat tmp
a b e c d
$ res=$(cat tmp)
$ echo $res
a b e c d
您需要引用变量$res
以保留空格。
$ cat file
a b e c d
$ res=$(cat file)
$ echo $res
a b e c d
$ echo "$res"
a b e c d
从man bash
下QUOTING
:
引用用于删除某些字符或单词对 shell 的特殊含义。引号可用于禁用对特殊字符的特殊处理,防止保留字被识别为保留字,并防止参数扩展。
上面 DEFINITIONS 下列出的每个元字符对 shell 都有特殊的含义,如果要表示它自己,则必须用引号引起来。
... \a alert (bell) \b backspace \e \E an escape character \f form feed \n new line \r carriage return \t horizontal tab \v vertical tab \\ backslash \' single quote \" double quote \nnn the eight-bit character whose value is the octal value nnn \xHH the eight-bit character whose value is the hexadecimal value HH \cx a control-x character ...
丢失选项卡的不是分配,而是调用echo
命令。
res
分配了一个包含选项卡的值。当你在 shell 中编写时$res
,这相当于在此时键入res
变量的内容。
所以:
$ echo $res
与以下内容相同:
$ echo a b e c d
(该行中的大空格是制表符,可以通过按 键入Ctrl+V Tab
)。如果您运行该命令,您还会得到:
a b e c d
所以你的问题实际上是:为什么选项卡会在命令的参数中丢失?
答案是命令(echo
在这种情况下)永远不会看到制表符,或者实际上是空格。Shell 将您的命令行解析为命令名称和参数列表。它使用空格(制表符和空格)将命令拆分为这些部分。然后它运行命令,将参数列表传递给它。
所以echo
它的参数是列表'a','b','e','c','d';它不知道最初将它们分开的是什么字符。
echo
然后输出它的每个参数,它们之间有一个空格。因此,您看到的输出。在原始命令行使用单个空格字符分隔每个参数的情况下,输出与输入匹配,因此看起来输入中的空格也在输出中 - 但它们不是:shell 吞噬了原始空格并echo
插入一些新的。
引号可用于使 shell 将多个“单词”视为单个参数。例如,如果您这样做:
$ echo a "b c" d
将 3 个参数传递给echo
:'a'、'b c' 和 'd'。中间参数包含 4 个空格;那些被传递给echo
,所以会出现在它的输出中。引号外的空格由 shell 用于拆分参数,因此不会传递给echo
. 因此输出为:
a b c d
要检查这种事情,使用一个命令会更清楚,该命令会准确显示它接收到的参数数量以及每个参数中的内容。这个 Perl 单行代码将做到这一点:
$ perl -MData::Dumper -E 'say Dumper \@ARGV' a b c d
$VAR1 = [
'a',
'b',
'c',
'd'
];
$ perl -MData::Dumper -E 'say Dumper \@ARGV' "a b c d"
$VAR1 = [
'a b c d'
];
$ perl -MData::Dumper -E 'say Dumper \@ARGV' a "b c" d
$VAR1 = [
'a',
'b c',
'd'
];
$ res="a b c d"
$ perl -MData::Dumper -E 'say Dumper \@ARGV' $res
$VAR1 = [
'a',
'b',
'c',
'd'
];
$ perl -MData::Dumper -E 'say Dumper \@ARGV' "$res"
$VAR1 = [
'a b c d'
];