如何调试返回值的bash函数,以及如何向变量添加换行符?

今天我在bash速成班。

这是一个bash函数,它通过echo返回一个值:

#!/bin/bash
get_hello_name() {
  echo 'Hello $1!'
}
msg=$(get_hello_name "x")
echo $msg

输出:

$ bash ./initial_script5.sh
Hello $1!

然后我错误地认为最后的回声被返回(我来自Java和Python),并试图使用回声来调试其余的功能。

然后我想知道为什么我不能在回声声明中打印换行符,尽管在这个问题中尝试了每一个建议。

这个脚本演示了这个问题:

#!/bin/bash
a_function() {
  echo "---In function"

  printf %"sn" hello world
  printf "Hellonworld"
  echo $'hellonworld'
  echo -e 'hellonworld'
}

echo "---Pre function"
printf %"sn" hello world
printf "Hellonworld"
echo $'hellonworld'
echo -e 'hellonworld'

x=$(a_function "x")
echo $x

echo "---Post function"
printf %"sn" hello world
printf "Hellonworld"
echo $'hellonworld'
echo -e 'hellonworld'


$ bash ./initial_script5.sh
---Pre function
hello
world
Hello
worldhello
world
hello
world
---In function hello world Hello worldhello world hello world
---Post function
hello
world
Hello
worldhello
world
hello
world

问题在于,函数中的所有回声在被单独修剪后连接在一起,然后作为整体返回。

因此,这引出了两个问题:如何调试一个返回值的函数,以及如何将新行添加到变量中(不是我甚至想要执行后者,但我想理解它)?


为什么换行符似乎从变量中消失

换行符实际上保留在变量中。 它们不显示,因为echo语句中的变量没有用双引号括起来。 从代码:

echo $x

当使用不带双引号的变量时,会执行分词。 在默认的$IFS$IFS wiki条目)下,这意味着所有的空白集合,包括换行符和制表符都被替换为单个空格。

为了避免这种情况,只需使用双引号,如下所示:

echo "$x"

通过这一次更改,脚本的输出将变为:

$ bash a,sh 
---Pre function
hello
world
Hello
worldhello
world
hello
world
---In function
hello
world
Hello
worldhello
world
hello
world
---Post function
hello
world
Hello
worldhello
world
hello
world

现在显示总是在变量x中的换行符。

除此之外,这两个词仍保持在一起

请注意,组合worldhello出现在一行中,因为这是代码要求的内容:

printf "Hellonworld"
echo $'hellonworld'

world之后printf不打印换行符。 因此,这个world与随后的hello出现在同一条线上。

详细信息的文档

man bash解释说,双引号可以抑制分词:

如果替换出现在双引号内,则不会对结果执行单词拆分和路径名扩展。

分词发生在变量扩展,命令替换和算术扩展之后:

shell扫描参数扩展,命令替换和算术扩展的结果,这些结果在双引号内没有出现,用于分词。

另一个微妙之处在于,只有在发生一些替换时才执行分词:

请注意,如果不发生扩展,则不会执行分割。

通常,当执行分词时,空格,制表符和换行符的所有字符串均由单个空格替换。 可以通过更改IFS变量的值来更改此默认行为:

shell将IFS的每个字符视为分隔符,并将其他扩展的结果拆分为这些字符上的单词。 如果IFS未设置,或者它的值完全是默认值,则忽略先前展开式结果开头和结尾处的空格,制表符和换行符序列,并忽略任何IFS字符序列的开始或结尾用来划分单词。 如果IFS的值不是默认值,则只要空格字符在IFS(IFS空白字符)的值中,空白字符空格和制表符的序列就会在字的开头和结尾被忽略。 IFS中不是IFS空白字符的任何字符以及任何相邻的IFS空白字符都会分隔一个字段。 一系列IFS空格字符也被视为分隔符。 如果IFS的值为空,则不会发生分词。

如何调试

  • 使用set -x

    将行set -x在您希望运行的代码的开头。 评估每条线的结果将在功能运行时显示,每条线都以PS4 (默认值为+ ,空格)作为区分正常输出的前缀。

    调试输出可以通过包含行set +x关闭。

    set -xset +x都可以在命令行上运行。

  • 使用stderr

    将调试输出发送到stderr (文件描述符2),如下所示:

    echo "My Debug Info" >&2
    

    默认情况下,管道和命令替换仅在stderr运行。 因此,发送到stderr信息默认情况下会出现在终端上。

  • 更多关于echo

    默认情况下, echo忽略转义字符,而序列n仅仅意味着后跟一个n

    $ echo "Hellonworld 4"
    Hellonworld 4
    

    要将n解释为换行符,请使用-e

    $ echo -e "Hellonworld 4"
    Hello
    world 4
    

    遵循John1024的提示后的工作代码(注意换行符由“ e选项打印在“1”行中,但不是“4”):

    #!/bin/bash
    a_function() {
        echo -e "Hellonworldn 1"
        echo "Hello"
        echo "world"
        echo "Hellonworld 4"
    }
    
    echo -e "Hellonworldn 1"
    echo "Hello"
    echo "world"
    echo "Hellonworld 4"
    
    x=$(a_function "x")
    echo "x-no-quotes>"
    echo $x                       #No new lines!
    echo "<x-no-quotes"
    
    echo "x-in-double-quotes>"
    echo "$x"                     #Yes new lines!
    echo "<x-in-double-quotes"
    
    echo -e "Hellonworldn 1"
    echo "Hello"
    echo "world"
    echo "Hellonworld 4"
    

    输出:

    Hello
    world
     1
    Hello
    world
    Hellonworld 4
    x-no-quotes>
    Hello world 1 Hello world Hellonworld 4
    <x-no-quotes
    x-in-double-quotes>
    Hello
    world
     1
    Hello
    world
    Hellonworld 4
    <x-in-double-quotes
    Hello
    world
     1
    Hello
    world
    Hellonworld 4
    

    你可能想用双引号echo "$x"来调用它。但是,如果你想显式地显示你在里面输入的内容,也就是所谓的字面表达式,使用单引号echo '$x'

    链接地址: http://www.djcxy.com/p/56801.html

    上一篇: How to debug a bash function that returns a value, and how to add newlines to a variable?

    下一篇: bash command to get the absolute path of a file: `%~dpnx1`