重击续行


158

您如何使用bash延续行?

我知道您可以这样做:

echo "continuation \
lines"
>continuation lines

但是,如果您缩进了代码,那么效果就不太好:

    echo "continuation \
    lines"
>continuation     lines

5
Google的《 Bash Shell样式指南》建议“如果您必须编写长度超过80个字符的字符串”的“此处”文档。参见@tripleee的答案
Trevor Boyd Smith,

google.github.io/styleguide/…-这是新文档中的直接链接
jcollum

Answers:


161

这就是你想要的

$       echo "continuation"\
>       "lines"
continuation lines

如果这创建了两个要回显的参数,而您只想要一个,那么我们来看一下字符串连接。在bash中,将两个字符串彼此并置:

$ echo "continuation""lines"
continuationlines

因此,没有缩进的续行是一种拆分字符串的方法:

$ echo "continuation"\
> "lines"
continuationlines

但是,当使用缩进时:

$       echo "continuation"\
>       "lines"
continuation lines

您将得到两个参数,因为这不再是串联。

如果您希望使用单个字符串来跨行,同时缩进但不能获得所有这些空格,则可以尝试的一种方法是抛弃连续行并使用变量:

$ a="continuation"
$ b="lines"
$ echo $a$b
continuationlines

这将使您能够以简洁的方式缩进代码,但会增加其他变量。如果将变量设置为局部变量,应该不会太差。


1
感谢您的帮助,但是尽管它确实删除了空格,但它们现在是单独的参数(Bash将第二行上的空格解释为参数分隔符),由于echo命令,现在只能正确打印。

1
哦,您想要一个(bash)字符串来跨越行!我现在明白了。
Ray Toal

4
具有一个变量的解决方案:s="string no. 1" s+="string no. 2" s+=" string no. 3" echo "$s"
Johnny Thunderman

30

在这里,带有<<-HERE终止符的文档非常适合缩进的多行文本字符串。它将从此处文档中删除所有前导选项卡。(不过,行终止符仍将保留。)

cat <<-____HERE
    continuation
    lines
____HERE

另请参见http://ss64.com/bash/syntax-here.html

如果您需要保留一些但不是全部前导空格,则可以使用类似

sed 's/^  //' <<____HERE
    This has four leading spaces.
    Two of them will be removed by sed.
____HERE

或用于tr摆脱换行符:

tr -d '\012' <<-____
    continuation
     lines
____

(第二行前面有一个制表符和一个空格;该破译符将在Heredoc终止符之前删除该制表符,而空格将保留。)

为了将复杂的长字符串包装在多行上,我喜欢printf

printf '%s' \
    "This will all be printed on a " \
    "single line (because the format string " \
    "doesn't specify any newline)"

如果您希望将非平凡的Shell脚本片段嵌入另一种语言,而宿主语言的语法不允许您使用here文档,例如a Makefile或in,则它也可以很好地工作Dockerfile

printf '%s\n' >./myscript \
    '#!/bin/sh` \
    "echo \"G'day, World\"" \
    'date +%F\ %T' && \
chmod a+x ./myscript && \
./myscript

对我不起作用。Ubuntu 16.04。我得到两行,而不是预期的串联一行。
Penghe Geng

@PengheGeng确实,这解决了消除缩进的问题,而不是将线连接在一起的问题。您仍然可以在行尾反斜杠以将两行连接在一起。
Tripleee '18

(但printf现在也请参见第一个示例。)
人间

12

您可以使用bash数组

$ str_array=("continuation"
             "lines")

然后

$ echo "${str_array[*]}"
continuation lines

还有一个额外的空间,因为(在bash手册之后):

如果单词用双引号引起来,则${name[*]}扩展为单个单词,每个数组成员的值都由IFS变量的第一个字符分隔

因此设置IFS=''以摆脱多余的空间

$ IFS=''
$ echo "${str_array[*]}"
continuationlines

4

在某些情况下,利用Bash的串联功能可能是合适的。

例:

temp='this string is very long '
temp+='so I will separate it onto multiple lines'
echo $temp
this string is very long so I will separate it onto multiple lines

在Bash手册页的“参数”部分中:

名称= [值] ...

...在赋值语句为外壳变量或数组索引赋值的情况下,可以使用+ =运算符追加或添加到变量的先前值。如果将+ =应用于已设置了整数属性的变量,则值将作为算术表达式求值,并添加到该变量的当前值中,该值也会被求值。当使用复合赋值将+ =应用于数组变量时(请参见下面的数组),该变量的值不会未设置(如使用=时的情况一样),并且新值将从比数组最大索引大一个的位置追加到数组中(用于索引数组)或作为附加键值对添加到关联数组中。 当将其应用于字符串值的变量时,值将被扩展并附加到变量的值上。


可能是此页面上的最佳建议。使用HEREDOC并将管道输送到<CR>的转换中是超级直观的操作,并且在字符串实际上需要具有离散放置的行分隔符时会失败。
ingyhere

2

我遇到一种情况,在这种情况下,我必须发送长消息作为命令参数的一部分,并且必须遵守行长限制。这些命令如下所示:

somecommand --message="I am a long message" args

我解决此问题的方法是将消息作为此处文档移出(建议使用@tripleee)。但是这里文档变成了标准输入,因此需要重新读入,我采用了以下方法:

message=$(
    tr "\n" " " <<- END
        This is a
        long message
END
)
somecommand --message="$message" args

这样做的好处是$message可以完全用作字符串常量,而不会出现多余的空格或换行符。

请注意,上面的实际消息行均以一个tab字符作为前缀,此处的文档本身将其删除(因为使用<<-)。末尾仍然有换行符,然后将其替换为dd空格。

另请注意,如果不删除换行符,则换行符将在"$message"展开时按原样显示。在某些情况下,您可以通过删除周围的双引号来解决$message,但该消息将不再是单个参数。


2

行的延续也可以通过巧妙地使用语法来实现。

在以下情况下echo

# echo '-n' flag prevents trailing <CR> 
echo -n "This is my one-line statement" ;
echo -n " that I would like to make."
This is my one-line statement that I would like to make.

对于vars:

outp="This is my one-line statement" ; 
outp+=" that I would like to make." ; 
echo -n "${outp}"
This is my one-line statement that I would like to make.

对于vars,另一种方法是:

outp="This is my one-line statement" ; 
outp="${outp} that I would like to make." ; 
echo -n "${outp}"
This is my one-line statement that I would like to make.

瞧!


1

您可以按照以下要求在缩进内使用换行符(不使用反斜杠)来简单地将其分开,如下所示:

例:

echo "continuation
of 
lines" | tr '\n' ' '

或者,如果它是变量定义,则换行符会自动转换为空格。因此,仅在适用时才去除多余的空格。

x="continuation
of multiple
lines"
y="red|blue|
green|yellow"

echo $x # This will do as the converted space actually is meaningful
echo $y | tr -d ' ' # Stripping of space may be preferable in this case

1

这并不是用户要求的,但是创建跨越多行的长字符串的另一种方法是通过逐步构建它,如下所示:

$ greeting="Hello"
$ greeting="$greeting, World"
$ echo $greeting
Hello, World

显然,在这种情况下,一次性构建起来会更简单,但是在处理较长的字符串时,这种样式非常轻巧且易于理解。


0

但是,如果您缩进了代码,那么效果就不太好:

    echo "continuation \
    lines"
>continuation     lines

尝试使用单引号和连接字符串:

    echo 'continuation' \
    'lines'
>continuation lines

注意:串联包含空格。


2
它适用于echo和string参数,但不适用于变量分配等其他功能。尽管问题不在于变量,但使用echo只是一个例子。而不是 echo 如果您有x=,则会得到错误:lines: command not found
LS

0

根据您将承受的风险种类以及对数据的了解和信任程度,可以使用简单的变量插值。

$: x="
    this
    is
       variably indented
    stuff
   "
$: echo "$x" # preserves the newlines and spacing

    this
    is
       variably indented
    stuff

$: echo $x # no quotes, stacks it "neatly" with minimal spacing
this is variably indented stuff

-2

这可能并不能真正回答您的问题,但是您可能仍会发现它很有用。

第一个命令创建第二个命令显示的脚本。

第三个命令使该脚本可执行。

第四个命令提供了一个用法示例。

john@malkovich:~/tmp/so$ echo $'#!/usr/bin/env python\nimport textwrap, sys\n\ndef bash_dedent(text):\n    """Dedent all but the first line in the passed `text`."""\n    try:\n        first, rest = text.split("\\n", 1)\n        return "\\n".join([first, textwrap.dedent(rest)])\n    except ValueError:\n        return text  # single-line string\n\nprint bash_dedent(sys.argv[1])'  > bash_dedent
john@malkovich:~/tmp/so$ cat bash_dedent 
#!/usr/bin/env python
import textwrap, sys

def bash_dedent(text):
    """Dedent all but the first line in the passed `text`."""
    try:
        first, rest = text.split("\n", 1)
        return "\n".join([first, textwrap.dedent(rest)])
    except ValueError:
        return text  # single-line string

print bash_dedent(sys.argv[1])
john@malkovich:~/tmp/so$ chmod a+x bash_dedent
john@malkovich:~/tmp/so$ echo "$(./bash_dedent "first line
>     second line
>     third line")"
first line
second line
third line

请注意,如果您确实要使用此脚本,则将可执行脚本移入~/bin该路径更有意义。

查看python参考以获取有关textwrap.dedent工作原理的详细信息。

如果使用$'...'"$(...)"会搞乱你,问另一个问题(每个构建一个)如果已经一上来有没有。提供指向您找到/询问的问题的链接可能很好,这样其他人将获得链接的参考。


6
意图很好,甚至可能有用的(尽管可能是有用的),OP询问有关基本bash语法的建议,并且您给了他一个使用OO范例,出色的流控制和导入的python函数定义。此外,您将可执行文件作为字符串插值的一部分进行了调用-有人问这种问题,在bash中肯定还看不到这种可执行文件。
Parthian Shot 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.