为什么echo"$ out"将输出拆分为多行,如果引号抑制字拆分?

run*_*gnu 0 bash quoting

我有一个非常简单的目录,其中包含"directory1"和"file2".后

out=`ls`
Run Code Online (Sandbox Code Playgroud)

我想打印我的变量:echo $out给:

directory1   file2
Run Code Online (Sandbox Code Playgroud)

echo "$out"给出:

directory1
file2
Run Code Online (Sandbox Code Playgroud)

所以使用引号给出了每个记录在单独行上的输出.正如我们所知,ls命令打印输出使用单行表示所有文件/目录(如果行足够大以包含输出),所以我希望使用双引号可以防止我的shell将单词拆分为单独的行,而省略引号则会拆分它们.请告诉我:为什么使用引号(用于防止分词)突然分裂输出?

Cha*_*ffy 6

论行为 ls

ls默认情况下,当输出到TTY时,只在一行上打印多个文件名.当输出到管道,文件或类似文件时,默认是将一行打印到文件.

引用POSIX标准ls,重点补充:

默认格式是每行列出一个条目到标准输出; 例外情况是终端或指定-C,-m或-x选项之一时.如果输出是终端,则格式是实现定义的.


文字问题(回复:引用)

这是将命令分成单独的参数的行为,导致它被放在一行!在本地,您的值跨越多行,因此未经修改地回显它(没有任何拆分)以这种方式打印它.

您的命令结果如下:

 out='directory1
 file2'
Run Code Online (Sandbox Code Playgroud)

运行时echo "$out",会打印出确切的内容.echo $out相反,当你跑步时,行为类似于:

echo "directory1" "file2"
Run Code Online (Sandbox Code Playgroud)

...因为字符串被分成两个元素,每个元素都作为完全不同的参数传递echo,以便echo在它看来合适时处理 - 在这种情况下,在同一行上打印这两个参数.


论分词的副作用

分词可能看起来像你想要的那样,但通常情况并非如此!考虑一些特殊问题:

  • 分词扩展了glob表达式:如果文件名包含*空格包围,*则会被当前目录中的文件列表替换,从而导致重复的结果.
  • 分词不支持引号或转义:如果文件名包含空格,则无法将该内部空格与分隔多个名称的空格区分开来.这与BashFAQ#50中描述的问题密切相关.

阅读目录

请参阅为什么不应该解析输出ls.简而言之 - 在您的示例中out=`ls`,out变量(作为字符串)无法以有用,可解析的方式存储所有可能的文件名.

例如,考虑一个这样创建的文件:

touch $'hello\nworld"three words here"'
Run Code Online (Sandbox Code Playgroud)

...该文件名包含空格和换行符,并且分词将无法在输出中正确地将其检测为单个名称ls.但是,您可以在数组中存储和处理它:

# create an array of filenames
names=( * )
if ! [[ -e $names || -L $names ]]; then  # this tests only the FIRST name
  echo "No names matched" >&2            # ...but that's good enough.
else
  echo "Found ${#files[@]} files" # print number of filenames
  printf '- %q\n' "${names[@]}"
fi
Run Code Online (Sandbox Code Playgroud)