Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 我刚刚分配了一个变量,但echo$variable显示了其他内容_Bash_Shell_Sh_Quoting - Fatal编程技术网

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

  • 最后,所有参数都传递给echo,echo将它们写出,并给出

    而不是变量的值

  • 当变量被引用时,它将:

  • 被它的价值所取代
  • 没有第二步

  • 这就是为什么您应该总是引用所有变量引用的原因,除非您特别需要分词和路径名扩展。类似这样的工具可以提供帮助,并在上述所有情况下警告缺少引号。

    除了将变量放入引号中,还可以使用
    tr
    转换变量的输出,并将空格转换为换行符

    $ echo $var | tr " " "\n"
    foo
    bar
    baz
    

    虽然这有点复杂,但它确实增加了输出的多样性,因为您可以替换任何字符作为数组变量之间的分隔符。

    您可能想知道为什么会发生这种情况。与一起,查找由以下人员编写的参考:

    为什么我需要写
    “$foo”
    ?没有引号会发生什么?
    $foo
    并不意味着“获取变量
    foo
    的值”。这意味着 更复杂的事情:

    • 首先,获取变量的值
    • 字段拆分:将该值视为以空格分隔的字段列表,并构建结果列表。例如,如果变量 包含
      foo*条​则此步骤的结果为3元素
      列表
      foo
      *
    • 文件名生成:将每个字段视为一个glob,即通配符模式,并将其替换为与此匹配的文件名列表 图案如果模式与任何文件都不匹配,则保留该模式 未经修改。在我们的示例中,这将导致包含
      foo
      的列表, 下面是当前目录中的文件列表,最后是
      。如果当前目录为空,则结果为
      foo
      *
    请注意,结果是字符串列表。在这种情况下有两种情况 shell语法:列表上下文和字符串上下文。字段拆分和 文件名生成只在列表上下文中发生,但这是大多数情况 时间。双引号分隔字符串上下文:整个 双引号字符串是单个字符串,不可拆分。(例外情况:
    “$@”
    展开到位置参数列表,例如,
    “$@”
    是 如果有三个位置变量,则相当于
    “$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