是否有类似于 heredoc (EOF) 中的 echo -n 的东西?

der*_*ugo 16 bash scripts

我正在编写一个巨大的脚本工厂脚本,为我的服务器生成大量维护脚本。

直到现在我写了一些需要写在一行中的行,echo -ne例如

echo -n "if (( " | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null

# Generate exitCode check for each Server
IFS=" "
COUNT=0
while read -r name ipAddr
do
    if(($COUNT != 0))
    then
        echo -n " || " | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
    fi

    echo -n "(\$"$name"_E != 0 && \$"$name"_E != 1)" | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null

    COUNT=$((COUNT+1))

    JOBSDONE=$((JOBSDONE+1))
    updateProgress $JOBCOUNT $JOBSDONE
done <<< "$(sudo cat /root/.virtualMachines)"

echo " ))" | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
Run Code Online (Sandbox Code Playgroud)

这会生成我(如果我的配置文件中有例如 2 个服务器)代码如下

if (( ($server1_E != 0 && $server1_E != 1) || ($server2_E != 0 && $server2_E != 1) ))
Run Code Online (Sandbox Code Playgroud)

所有其他不需要这种内联编写代码的代码块我使用 heredocs 生成,因为我发现它们的编写和维护方式更好。例如,在上层代码之后,我生成了其余的代码

cat << EOF | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
then
    # Print out ExitCode legend
    echo " ExitCode 42 - upgrade failed"
    echo " ExitCode 43 - Upgrade failed"
    echo " ExitCode 44 - Dist-Upgrade failed"
    echo " ExitCode 45 - Autoremove failed"
    echo ""
    echo ""
fi
EOF
Run Code Online (Sandbox Code Playgroud)

所以最终的代码块看起来像

if (( ($server1_E != 0 && $server1_E != 1) || ($server2_E != 0 && $server2_E != 1) ))
then
    # Print out ExitCode legend
    echo " ExitCode 42 - upgrade failed"
    echo " ExitCode 43 - Upgrade failed"
    echo " ExitCode 44 - Dist-Upgrade failed"
    echo " ExitCode 45 - Autoremove failed"
    echo ""
    echo ""
fi
Run Code Online (Sandbox Code Playgroud)

我的问题
有没有办法让heredoc 的行为类似于echo -ne没有行尾符号的情况?

cho*_*oba 10

不,heredoc 总是以换行符结尾。但是您仍然可以删除最后一个换行符,例如使用 Perl:

cat << 'EOF' | perl -pe 'chomp if eof'
First line
Second line
EOF
Run Code Online (Sandbox Code Playgroud)
  • -p逐行读取输入,运行 中指定的代码-e,并打印(可能修改过的)行
  • chomp删除最后的换行符(如果存在),eof在文件末尾返回 true。


Ser*_*nyy 7

有没有办法让heredoc的行为类似于没有行尾符号的echo -ne?

简短的回答是,heredoc 和 herestrings 只是以这种方式构建的,所以不 - here-doc 和 herestring 将始终添加一个尾随换行符,并且没有选项或本机方法可以禁用它(也许在未来的 bash 版本中会有?)。

但是,通过仅使用 bash 的方式来处理它的一种方法是通过标准while IFS= read -r方法读取 heredoc 给出的内容,但添加延迟并通过printf不带尾随换行符的方式打印最后一行。以下是仅使用 bash 可以做的事情:

#!/usr/bin/env bash

while true
do
    IFS= read -r line || { printf "%s" "$delayed";break;}
    if [ -n "$delayed" ]; 
    then
        printf "%s\n" "$delayed"
    fi
    delayed=$line
done <<EOF
one
two
EOF
Run Code Online (Sandbox Code Playgroud)

你在这里看到的是通常的 while 循环IFS= read -r line方法,但是每一行都存储到一个变量中,因此延迟了(所以我们跳过打印第一行,存储它,只有当我们阅读第二行时才开始打印)。这样我们就可以捕获最后一行,当下一次迭代read返回退出状态 1 时,那是我们通过printf. 冗长?是的。但它有效:

$ ./strip_heredoc_newline.sh                                      
one
two$ 
Run Code Online (Sandbox Code Playgroud)

注意$提示字符被向前推,因为没有换行符。作为奖励,这个解决方案是便携和POSIX十岁上下,所以它应该在工作kshdash为好。

$ dash ./strip_heredoc_newline.sh                                 
one
two$
Run Code Online (Sandbox Code Playgroud)


kas*_*erd 6

我建议您尝试不同的方法。而不是从多个 echo 语句和 heredocs 中拼凑生成的脚本。我建议您尝试使用单个 heredoc。

您可以在 heredoc 中使用变量扩展和命令替换。就像在这个例子中:

#!/bin/bash
cat <<EOF
$USER $(uname)
EOF
Run Code Online (Sandbox Code Playgroud)

我发现这通常会导致比逐个生成输出更具可读性的最终结果。

此外,您似乎忘记了#!脚本开头的那一行。该#!行在任何格式正确的脚本中都是强制性的。尝试运行没有该#!行的脚本只会在您从处理格式错误的脚本的 shell 中调用它时才有效,即使在这种情况下,它最终可能会被与您预期不同的 shell 解释。


Dav*_*ter 5

Heredocs 总是以换行符结尾,但您可以简单地将其删除。我知道的最简单的方法是使用head程序:

head -c -1 <<EOF | sudo tee file > /dev/null
my
heredoc
content
EOF
Run Code Online (Sandbox Code Playgroud)