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

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

我今天上的是速成班。

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

1
2
3
4
5
6
#!/bin/bash
get_hello_name() {
  echo 'Hello $1!'
}
msg=$(get_hello_name"x")
echo $msg

输出:

1
2
$ bash ./initial_script5.sh
Hello $1!

然后我错误地认为最后一个回音是返回的(我来自Java和Python),并试图用ECHO调试函数的其余部分。

然后我想知道为什么我不能在回音陈述中打印出新行,尽管我尝试了这个问题中的每一个建议。

此脚本演示了问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#!/bin/bash
a_function() {
  echo"---In function"

  printf %"s
"
hello world
  printf"Hello
world"

  echo $'hello
world'

  echo -e 'hello
world'

}

echo"---Pre function"
printf %"s
"
hello world
printf"Hello
world"

echo $'hello
world'

echo -e 'hello
world'


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

echo"---Post function"
printf %"s
"
hello world
printf"Hello
world"

echo $'hello
world'

echo -e 'hello
world'



$ 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语句中的变量没有用双引号括起来。从代码:

1
echo $x

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

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

1
echo"$x"

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ 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出现在一行上,因为代码要求这样做:

1
2
3
4
printf"Hello
world"

echo $'hello
world'

printf不在world之后打印新行。因此,world与后面的hello出现在同一条线上。

详细资料文件

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

If the substitution appears within double quotes, word splitting and pathname expansion are not performed on the results.

单词拆分发生在变量展开后,命令替换和算术展开:

The shell scans the results of parameter expansion, command
substitution, and arithmetic expansion that did not occur within
double quotes for word splitting.

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

Note that if no expansion occurs, no splitting is performed.

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

The shell treats each character of IFS as a delimiter, and splits the
results of the other expansions into words on these characters. If
IFS is unset, or its value is exactly , the
default, then sequences of space, tab, and newline at the
beginning and end of the results of the previous expansions are
ignored, and any sequence of IFS characters not at the beginning or
end serves to delimit words. If IFS has a value other than the
default, then sequences of the whitespace characters space and tab are
ignored at the beginning and end of the word, as long as
the whitespace character is in the value of IFS (an IFS whitespace
character). Any character in IFS that is not IFS whitespace, along
with any adjacent IFS whitespace characters, delimits a field. A
sequence of IFS whitespace characters is also treated as a delimiter. If the value of IFS is null, no word splitting occurs.

如何调试

  • 使用set -x

    将行set -x放在要运行的代码的开头。当函数运行时,将显示评估每行的结果,每行前面都有PS4(默认值为+,空格),以将其与正常输出区分开来。

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

    set -xset +x都在命令行上工作。

  • 使用stderr

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

    1
    echo"My Debug Info">&2

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

  • 更多关于echo

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

    1
    2
    3
    4
    $ echo"Hello
    world 4"

    Hello
    world 4

    要将
    解释为新行,请使用-e

    1
    2
    3
    4
    $ echo -e"Hello
    world 4"

    Hello
    world 4


    你可以用双引号来称呼它echo"$x"但是,如果您想显式地显示您在其中键入的内容,也被称为文字表达式,请使用单引号echo '$x'


    遵循john1024提示后的工作代码(注意,由于e选项,新行打印在"1"行,而不是"4"):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    #!/bin/bash
    a_function() {
        echo -e"Hello
    world
     1"

        echo"Hello"
        echo"world"
        echo"Hello
    world 4"

    }

    echo -e"Hello
    world
     1"

    echo"Hello"
    echo"world"
    echo"Hello
    world 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
    world
     1"

    echo"Hello"
    echo"world"
    echo"Hello
    world 4"

    输出:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    Hello
    world
     1
    Hello
    world
    Hello
    world 4
    x-no-quotes>
    Hello world 1 Hello world Hello
    world 4
    <x-no-quotes
    x-in-double-quotes>
    Hello
    world
     1
    Hello
    world
    Hello
    world 4
    <x-in-double-quotes
    Hello
    world
     1
    Hello
    world
    Hello
    world 4