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

时间:2015-01-10 01:55:18

标签: bash scripting ubuntu-14.04

我今天参加了一个bash速成课程。

这是一个bash函数returns a value,通过echo:

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

输出:

$ bash ./initial_script5.sh
Hello $1!

然后我错误地认为返回了 last echo(我来自Java和Python),并且正在尝试使用echo来调试函数的其余部分。

然后我想知道为什么尽管在this question中尝试了每一个建议,我仍然无法在echo语句中打印换行符。

此脚本演示了此问题:

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

  printf %"s\n" hello world
  printf "Hello\nworld"
  echo $'hello\nworld'
  echo -e 'hello\nworld'
}

echo "---Pre function"
printf %"s\n" hello world
printf "Hello\nworld"
echo $'hello\nworld'
echo -e 'hello\nworld'

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

echo "---Post function"
printf %"s\n" hello world
printf "Hello\nworld"
echo $'hello\nworld'
echo -e 'hello\nworld'


$ 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

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

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

3 个答案:

答案 0 :(得分:7)

为什么新行似乎从变量

中消失

新行实际上保留在变量中。它们不显示,因为echo语句中的变量未包含在双引号中。从代码:

echo $x

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

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

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 "Hello\nworld"
echo $'hello\nworld'

printfworld不会打印换行符。因此,world与后面的hello显示在同一行。

详细信息的文档

man bash解释双引号会抑制单词分裂:

  

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

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

  

shell扫描参数扩展命令的结果   替换和未发生的算术扩展   用于分词的双引号。

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

  

请注意,如果没有发生扩展,则不执行拆分。

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

  

shell将IFS的每个字符视为分隔符,并将其拆分   其他扩展成为这些字符的单词的结果。如果   IFS未设置,或者它的值正好是   默认,然后是空格,制表符和换行符的序列   以前扩展的结果的开始和结束   忽略,任何IFS字符序列不在开头或   结尾用于划分单词。如果IFS的值不是   默认情况下,然后是空白字符空格和制表符的序列   在这个词的开头和结尾都被忽略了,只要   空白字符是IFS的值(IFS空格   字符)。 IFS中的任何字符都不是IFS空格   使用任何相邻的IFS空白字符,分隔字段。一个   IFS空白字符序列也被视为分隔符。如果IFS的值为null,则不会发生分词。

如何调试

  1. 使用set -x

    将行set -x放在要运行的代码的开头。评估每一行的结果将在函数运行时显示,每个都以PS4(默认为+,空格)开头,以区别于正常输出。

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

    set -xset +x也适用于命令行。

  2. 使用stderr

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

    echo "My Debug Info" >&2
    

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

  3. 更多关于echo

    默认情况下,echo会忽略转义字符,序列\n只表示\后跟n

    $ echo "Hello\nworld 4"
    Hello\nworld 4
    

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

    $ echo -e "Hello\nworld 4"
    Hello
    world 4
    

答案 1 :(得分:0)

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

#!/bin/bash
a_function() {
    echo -e "Hello\nworld\n 1"
    echo "Hello"
    echo "world"
    echo "Hello\nworld 4"
}

echo -e "Hello\nworld\n 1"
echo "Hello"
echo "world"
echo "Hello\nworld 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 "Hello\nworld\n 1"
echo "Hello"
echo "world"
echo "Hello\nworld 4"

输出:

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

答案 2 :(得分:0)

你可能想用双引号来调用它 echo "$x" 但是,如果您想要明确显示您键入的内容,也称为文字表达式,请使用单引号echo '$x'