Bash 我刚刚分配了一个变量,但echo$variable显示了其他内容
下面是一系列情况,Bash 我刚刚分配了一个变量,但echo$variable显示了其他内容,bash,shell,sh,quoting,Bash,Shell,Sh,Quoting,下面是一系列情况,echo$var可以显示与刚才分配的值不同的值。无论指定的值是“双引号”、“单引号”还是“无引号”,都会发生这种情况 如何让shell正确设置变量 星号 预期的输出是/*Foobar是免费软件*/,但我得到了一个文件名列表: $ var="/* Foobar is free software */" $ echo $var /bin /boot /dev /etc /home /initrd.img /lib /lib64 /media /mnt /opt /proc ...
echo$var
可以显示与刚才分配的值不同的值。无论指定的值是“双引号”、“单引号”还是“无引号”,都会发生这种情况
如何让shell正确设置变量
星号
预期的输出是/*Foobar是免费软件*/
,但我得到了一个文件名列表:
$ var="/* Foobar is free software */"
$ echo $var
/bin /boot /dev /etc /home /initrd.img /lib /lib64 /media /mnt /opt /proc ...
方括号
预期值是[a-z]
,但有时我会得到一个字母
$ var=[a-z]
$ echo $var
c
换行符(换行符)
预期值是一个单独行的列表,但所有值都在一行上
$ cat file
foo
bar
baz
$ var=$(cat file)
$ echo $var
foo bar baz
多个空格
我希望有一个仔细对齐的表头,但相反,多个空格要么消失,要么被折叠成一个
$ var=" title | count"
$ echo $var
title | count
选项卡
我希望有两个制表符分隔的值,但是我得到了两个空格分隔的值
$ var=$'key\tvalue'
$ echo $var
key value
在上述所有情况下,变量设置正确,但读取不正确!正确的方法是在引用时使用双引号:
echo "$var"
这给出了所有示例中的预期值。始终引用变量引用
为什么? 当一个变量未被引用时,它将:
/*Foobar是免费软件*/
之后:/*
,Foobar
,是
,免费
,软件
,*/
/*
之后:/bin
,/boot
,/dev
,/etc
,/home
这就是为什么您应该总是引用所有变量引用的原因,除非您特别需要分词和路径名扩展。类似这样的工具可以提供帮助,并在上述所有情况下警告缺少引号。除了将变量放入引号中,还可以使用
tr
转换变量的输出,并将空格转换为换行符
$ echo $var | tr " " "\n"
foo
bar
baz
虽然这有点复杂,但它确实增加了输出的多样性,因为您可以替换任何字符作为数组变量之间的分隔符。您可能想知道为什么会发生这种情况。与一起,查找由以下人员编写的参考: 为什么我需要写
“$foo”
?没有引号会发生什么?
$foo
并不意味着“获取变量foo
的值”。这意味着
更复杂的事情:
- 首先,获取变量的值李>
- 字段拆分:将该值视为以空格分隔的字段列表,并构建结果列表。例如,如果变量
包含
foo*条代码>则此步骤的结果为3元素 列表
,foo
,*
李>栏
- 文件名生成:将每个字段视为一个glob,即通配符模式,并将其替换为与此匹配的文件名列表 图案如果模式与任何文件都不匹配,则保留该模式 未经修改。在我们的示例中,这将导致包含
的列表, 下面是当前目录中的文件列表,最后是foo
。如果当前目录为空,则结果为条
,foo
,*
条
- 文件名生成:将每个字段视为一个glob,即通配符模式,并将其替换为与此匹配的文件名列表 图案如果模式与任何文件都不匹配,则保留该模式 未经修改。在我们的示例中,这将导致包含
“$@”
展开到位置参数列表,例如,“$@”
是
如果有三个位置变量,则相当于“$1”“$2”“$3”
参数(请参阅)
使用$(foo)
或
`foo`
。另一方面,不要使用`foo`
:它的引用规则是
怪异且不可移植,所有现代shell都支持$(foo)
,其中
除了有直观的引用规则外,它是绝对等效的
算术代换的输出也经历相同的过程
扩展,但这通常不是一个问题,因为它只包含
不可扩展字符(假设IFS
不包含数字或
-
)
请参阅,以了解有关的更多详细信息
当你可以省去引号的时候
除非你的意思是要让这些繁琐的事情发生,记得
始终在变量和命令替换前后使用双引号。做
注意:省略引号不仅会导致错误,还会导致错误
echo$var
输出在很大程度上取决于IFS
变量的值。默认情况下,它包含空格、制表符和换行符:
[ks@localhost ~]$ echo -n "$IFS" | cat -vte
^I$
这意味着,当shell进行字段拆分(或单词拆分)时,它会将所有这些字符用作单词分隔符。当引用一个没有双引号的变量来回显它($var
)时会发生这种情况,因此预期的输出会被改变
防止分词的一种方法(除了使用双引号外)是将IFS
设置为null。见:
如果IFS的值为空,则不应执行字段拆分
设置为n
[ks@localhost ~]$ echo -n "$IFS" | cat -vte
^I$
IFS=
[ks@localhost ~]$ echo -n "$IFS" | cat -vte
^I$
[ks@localhost ~]$ var=$'key\nvalue'
[ks@localhost ~]$ echo $var
key value
[ks@localhost ~]$ IFS=
[ks@localhost ~]$ echo $var
key
value
[ks@localhost ~]$
echo "${var}"
$ vars="-e -n -a"
$ echo $vars # breaks because -e and -n can be treated as arguments to echo
-a
$ echo "$vars"
-e -n -a
$ vars="-n"
$ echo $vars
$ ## not even an empty line was printed
$ vars="-n"
$ printf '%s\n' "$vars"
-n
$ test=$(/usr/local/bin/docker-compose exec db bash -c "echo 1")
$ echo "${test}b"
b
echo "${test}" | cat -vte
1^M$
$ test=$(/usr/local/bin/docker-compose exec -T db bash -c "echo 1")
$ echo "${test}b"
1b