如何调试返回值的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 -x
和set +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'
上一篇: 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`