将复杂的多行字符串写入变量的干净方法

Chr*_*mbo 120 bash

我需要将一些复杂的 xml 写入 bash 脚本中的变量。xml 需要在 bash 脚本中可读,因为这是 xml 片段所在的位置,而不是从另一个文件或源读取。

所以我的问题是,如果我有一个很长的字符串,我想在我的 bash 脚本中成为人类可读的,那么最好的方法是什么?

理想情况下,我想要:

  • 不必转义任何字符
  • 让它跨越多行,使其易于阅读
  • 保持缩进

这可以用EOF或其他东西来完成,谁能给我举个例子?

例如

String = <<EOF
 <?xml version="1.0" encoding='UTF-8'?>
 <painting>
   <img src="madonna.jpg" alt='Foligno Madonna, by Raphael'/>
   <caption>This is Raphael's "Foligno" Madonna, painted in
   <date>1511</date>-<date>1512</date>.</caption>
 </painting>
EOF
Run Code Online (Sandbox Code Playgroud)

Den*_*son 156

这会将您的文本放入您的变量中,而无需转义引号。它还将处理不平衡的引号(撇号,即')。在标记 (EOF) 周围加上引号可防止文本进行参数扩展。将-d''导致其读取多个线(忽略新行)。read是内置的 Bash,因此它不需要调用外部命令,例如cat.

IFS='' read -r -d '' String <<"EOF"
<?xml version="1.0" encoding='UTF-8'?>
 <painting>
   <img src="madonna.jpg" alt='Foligno Madonna, by Raphael'/>
   <caption>This is Raphael's "Foligno" Madonna, painted in
   <date>1511</date>-<date>1512</date>.</caption>
 </painting>
EOF
Run Code Online (Sandbox Code Playgroud)

  • 如果您使用这个多行 `String` 变量写入文件,请将变量放在 "QUOTES" 周围,例如 `echo "${String}" &gt; /tmp/multiline_file.txt` 或 `echo "${String }" | 三通/tmp/multiline_file.txt`。我花了一个多小时才找到那个。 (13认同)
  • 我尝试在 `set -e` 时使用上面的语句。似乎 `read` 总是返回非零值。您可以使用 `! 读-d ......` (12认同)
  • 并且永远不要缩进第二个 EOF ......(涉及多个表头刘海) (11认同)
  • `cat` 是一个外部命令。不使用它可以节省这样做。另外,有些人认为,如果您使用 cat 的参数少于两个“你做错了”(这与“无用地使用 `cat`”不同)。 (5认同)
  • @DennisWilliamson:shell 中的“正确”错误处理非常乏味。`set -e` 不完美,偶尔会设置陷阱,但使脚本更加可靠。 (3认同)
  • @Andrew:可靠,直到它不是 (2认同)
  • @krissi:您可以使用 `read -d '' String &lt;&lt;"EOF" ||:` 来避免错误陷阱。 (2认同)

jos*_*chi 34

你已经快到了。要么使用cat来组装字符串,要么引用整个字符串(在这种情况下,您必须对字符串中的引号进行转义):

#!/bin/sh
VAR1=$(cat <<EOF
<?xml version="1.0" encoding='UTF-8'?>
<painting>
  <img src="madonna.jpg" alt='Foligno Madonna, by Raphael'/>
  <caption>This is Raphael's "Foligno" Madonna, painted in
  <date>1511</date>-<date>1512</date>.</caption>
</painting>
EOF
)

VAR2="<?xml version=\"1.0\" encoding='UTF-8'?>
<painting>
  <img src=\"madonna.jpg\" alt='Foligno Madonna, by Raphael'/>
  <caption>This is Raphael's \"Foligno\" Madonna, painted in
  <date>1511</date>-<date>1512</date>.</caption>
</painting>"

echo "${VAR1}"
echo "${VAR2}"
Run Code Online (Sandbox Code Playgroud)

  • 它适用于脚本,但不适用于 Bash 提示符。抱歉没有说清楚。 (2认同)
  • 最好将 EOF 引用为 `'EOF'` 或 `"EOF"`,否则 shell 变量将被解析。 (2认同)

小智 16

#!/bin/sh

VAR1=`cat <<EOF
<?xml version="1.0" encoding='UTF-8'?>
<painting>
  <img src="madonna.jpg" alt='Foligno Madonna, by Raphael'/>
  <caption>This is Raphael's "Foligno" Madonna, painted in
  <date>1511</date>-<date>1512</date>.</caption>
</painting>
EOF
`
echo "VAR1: ${VAR1}"
Run Code Online (Sandbox Code Playgroud)

这在 Bourne shell 环境中应该可以正常工作

  • +1 此解决方案允许变量替换,如 ${foo} (2认同)
  • 从什么时候开始弃用/不鼓励反引号?只是好奇 (2认同)

F. *_*uri 6

还有另一种方法来做同样的事情......

我喜欢使用变量和特殊的<<-who在每行开头删除制表以允许脚本缩进:

#!/bin/bash

mapfile Pattern <<-eof
        <?xml version="1.0" encoding='UTF-8'?>
        <painting>
          <img src="%s" alt='%s'/>
          <caption>%s, painted in
          <date>%s</date>-<date>%s</date>.</caption>
        </painting>
        eof

while IFS=";" read file alt caption start end ;do
    printf "${Pattern[*]}" "$file" "$alt" "$caption" "$start" "$end"
  done <<-eof
        madonna.jpg;Foligno Madonna, by Raphael;This is Raphael's "Foligno" Madonna;1511;1512
        eof
Run Code Online (Sandbox Code Playgroud)

警告:前面没有空格eof只有表格

<?xml version="1.0" encoding='UTF-8'?>
 <painting>
   <img src="madonna.jpg" alt='Foligno Madonna, by Raphael'/>
   <caption>This is Raphael's "Foligno" Madonna, painted in
   <date>1511</date>-<date>1512</date>.</caption>
 </painting>
Run Code Online (Sandbox Code Playgroud) 一些解释:
  • mapfile在一个数组中读取整个here 文档
  • 语法"${Pattern[*]}"确实将此数组转换为字符串。
  • 我使用IFS=";"是因为;在必需的字符串中没有
  • 语法while IFS=";" read file ...防止IFS脚本的其余部分被修改。在这种情况下,只read使用修改后的IFS.
  • 没有叉子。