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

ali*_*ind 7 bash scripting ubuntu-14.04

我今天正在参加一个bash速成课程.

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

#!/bin/bash
get_hello_name() {
  echo 'Hello $1!'
}
msg=$(get_hello_name "x")
echo $msg
Run Code Online (Sandbox Code Playgroud)

输出:

$ bash ./initial_script5.sh
Hello $1!
Run Code Online (Sandbox Code Playgroud)

然后我错误地认为最后一个回声被返回(我来自Java和Python),并且试图使用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
Run Code Online (Sandbox Code Playgroud)

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

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

Joh*_*024 10

为什么新行似乎从变量中消失了

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

echo $x
Run Code Online (Sandbox Code Playgroud)

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

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

echo "$x"
Run Code Online (Sandbox Code Playgroud)

通过该单个更改,脚本的输出将变为:

$ 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
Run Code Online (Sandbox Code Playgroud)

x现在显示始终位于变量中的换行符.

旁白:两个字仍然串在一起

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

printf "Hello\nworld"
echo $'hello\nworld'
Run Code Online (Sandbox Code Playgroud)

printf后不打印一个换行符world.因此,它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 -x并且set +x两者也在命令行上工作.

  2. 使用 stderr

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

    echo "My Debug Info" >&2
    
    Run Code Online (Sandbox Code Playgroud)

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

更多关于 echo

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

$ echo "Hello\nworld 4"
Hello\nworld 4
Run Code Online (Sandbox Code Playgroud)

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

$ echo -e "Hello\nworld 4"
Hello
world 4
Run Code Online (Sandbox Code Playgroud)