无法缩进heredoc以匹配代码块的缩进

无法缩进heredoc以匹配代码块的缩进

如果说脚本编写存在“第一世界问题”,那么就是这个了。

我正在更新的脚本中有以下代码:

if [ $diffLines -eq 1 ]; then
        dateLastChanged=$(stat --format '%y' /.bbdata | awk '{print $1" "$2}' | sed 's/\.[0-9]*//g')

        mailx -r "Systems and Operations <sysadmin@[redacted].edu>" -s "Warning Stale BB Data" jadavis6@[redacted].edu <<EOI
        Last Change: $dateLastChanged

        This is an automated warning of stale data for the UNC-G Blackboard Snapshot process.
EOI

else
        echo "$diffLines have changed"
fi

该脚本发送电子邮件没有问题,但 mailx 命令嵌套在 if 语句中,因此我似乎有两个选择:

  1. EOI一个新行并打破缩进模式或
  2. 保持缩进,但使用 echo 语句之类的东西让 mailx 吸收我的电子邮件。

我对heredoc的替代方案持开放态度,但如果有办法解决这个问题,它是我的首选语法。

答案1

您可以将here-doc运算符更改为<<-。然后您可以缩进此处文档和分隔符带选项卡:

#! /bin/bash
cat <<-EOF
    indented
    EOF
echo Done

注意你必须使用标签,而不是空格,来缩进此处文档和分隔符。这意味着上面的示例将无法复制(Stack Exchange 用空格替换制表符)。如果在第一个分隔符周围添加任何引号EOF,则参数扩展、命令替换和算术扩展将不会生效。

答案2

如果您不需要在此处文档中进行命令替换和参数扩展,则可以通过在分隔符中添加前导空格来避免使用制表符:

$     cat << '    EOF'
>         indented
>     EOF
        indented
$     cat << '    EOF' | sed -r 's/^ {8}//'
>         unindented
>     EOF
unindented

不过,我无法找到使用此技巧并保持参数扩展的方法。

答案3

尝试这个:

sed 's/^ *//' >> ~/Desktop/text.txt << EOF
    Load time-out reached and nothing to resume.
    $(date +%T) - Transmission-daemon exiting.
EOF

答案4

这个答案是 GNU-Bash 特定的。

诀窍是我们使用<<<Bash 提供的单字here-doc,并将其设为多行项目。

我们还避免了 UUoC:我们不需要一个cat流程来将输入提供给sed

$ sed '1d;s/^    //' <<<"
    {
       TERM=$TERM
    }
    bye"

输出显示前导四空格缩进已删除并$TERM扩展:

{
   TERM=xterm-256color
}
bye

1d中的命令是sed删除第一个空行,该空行之所以存在,是因为我们的引用文字在开始引号后以换行符开头。

当然,在真实的脚本中,这是凹痕ed——请原谅我,在照顾ed——我们将大括号与命令对齐sed,该命令将在循环或条件内缩进。

如果我们以分隔符开始数据的每一行,那么简单的sed替换将删除可变数量的缩进,以便块可以在缩进级别之间自由移动:

while command ; do
    if condition ; then
        variable=$(sed '1d;s/^.*|//' <<<"
                  |{
                  |   TERM=$TERM
                  |}
                  |bye
                  ")
    fi
done

最后一个想法是将缩进魔法放入一个用作某种宏的变量中:

# put in some common definitions library section
indent='sed 1d;s/^.*|//'

# ...

while command ; do
    if condition ; then
        variable=$($indent <<<"
                  |{
                  |   TERM=$TERM
                  |}
                  |bye
                  ")
    fi
done

我们可以通过编写一个好的老式函数来改进这一点:

# put in some common definitions library section
ind()
{
   sed '1d;s/^.*|//' <<<$1
}

# ...

while command ; do
    if condition ; then
        variable=$(ind "
                  |{
                  |   TERM=$TERM
                  |}
                  |bye
                  ")
    fi
done

然后我们就完全抽象出来了<<<

相关内容