Não, heredoc sempre termina em uma nova linha. Mas você ainda pode remover a última nova linha, por exemplo, com Perl:
cat << 'EOF' | perl -pe 'chomp if eof'
First line
Second line
EOF
Estou escrevendo em um roteiro enorme de fábrica de scripts, gerando muitos scripts de manutenção para meus servidores.
Até agora, escrevo algumas linhas que precisam ser escritas em uma linha com echo -ne
, por exemplo,
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
isso me gera (se houver, por exemplo, dois servidores no meu arquivo de configuração) como
if (( ($server1_E != 0 && $server1_E != 1) || ($server2_E != 0 && $server2_E != 1) ))
Todos os outros blocos de código que não precisam dessa escrita de código in-line eu produzo com heredocs, pois acho que é melhor escrever e manter. Por exemplo. depois do código superior eu tenho o resto gerado como
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
Assim, o bloco de código final parece
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
Minha pergunta
Existe uma maneira de ter um heredoc se comportando de maneira semelhante a echo -ne
sem o símbolo de fim de linha?
Não, heredoc sempre termina em uma nova linha. Mas você ainda pode remover a última nova linha, por exemplo, com Perl:
cat << 'EOF' | perl -pe 'chomp if eof'
First line
Second line
EOF
Existe alguma maneira de um heredoc se comportar de maneira semelhante ao echo -ne sem o símbolo de fim de linha?
Resposta curta é que heredoc e herestrings são construídos dessa forma, então não - aqui-doc e herestring estarão adicionando uma nova linha à direita sempre e não há opção ou uma maneira nativa de desativá-la (talvez Haverá no futuro liberações bash?).
No entanto, uma maneira de abordá-lo através de formas bash-only seria ler o que heredoc dá através do método padrão while IFS= read -r
, mas adicionar um atraso e imprimir a última linha via printf
sem a nova linha. Veja o que se pode fazer com o bash-only:
#!/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
O que você vê aqui é o usual while loop com a abordagem IFS= read -r line
, porém cada linha é armazenada em uma variável e assim atrasada (então pulamos a impressão da primeira linha, armazenamos e começamos a imprimir somente quando lemos segunda linha). Dessa forma, podemos capturar a última linha e, quando estiver na próxima iteração, read
retornará o status de saída 1, quando imprimiremos a última linha sem nova linha via printf
. Verboso? sim. Mas funciona:
$ ./strip_heredoc_newline.sh
one
two$
Observe que o caractere de prompt $
está sendo avançado, já que não há nova linha. Como bônus, esta solução é portátil e POSIX-ish, então deve funcionar em ksh
e dash
também.
$ dash ./strip_heredoc_newline.sh
one
two$
Eu recomendo que você tente uma abordagem diferente. Em vez de juntar seu script gerado a partir de várias instruções echo e heredocs. Eu sugiro que você tente usar um único heredoc.
Você pode usar a expansão de variáveis e a substituição de comandos dentro de um heredoc. Como neste exemplo:
#!/bin/bash
cat <<EOF
$USER $(uname)
EOF
Eu acho que isso geralmente leva a resultados finais muito mais legíveis do que produzir a saída peça por peça.
Além disso, parece que você esqueceu a linha #!
no início de seus scripts. A linha #!
é obrigatória em qualquer script formatado corretamente. A tentativa de executar um script sem a linha #!
só funcionará se você chamá-lo de um shell que funcione com scripts mal formatados e, mesmo nesse caso, pode acabar sendo interpretado por um shell diferente do desejado.
Você pode remover as novas linhas da maneira que preferir, bastando que tr
seja mais simples. Isso removeria todas as novas linhas, é claro.
$ tr -d '\n' <<EOF
if ((
EOF
Mas, a declaração if que você está construindo não exige isso, a expressão aritmética (( .. ))
deve funcionar bem mesmo que contenha novas linhas.
Então, você poderia fazer
cat <<EOF
if ((
EOF
for name in x y; do
cat << EOF
( $${name}_E != 0 && $${name}_E != 1 ) ||
EOF
done
cat <<EOF
0 )) ; then
echo do something
fi
EOF
produzindo
if ((
( $x_E != 0 && $x_E != 1 ) ||
( $y_E != 0 && $y_E != 1 ) ||
0 )) ; then
echo do something
fi
Construí-lo em um loop ainda faz feio, no entanto. O || 0
está lá, é claro, para que não seja necessário especificar a primeira ou a última linha.
Além disso, você tem esse | sudo tee ...
em cada saída. Acho que poderíamos nos livrar disso abrindo um redirecionamento apenas uma vez (com a substituição do processo) e usando isso para a impressão posterior:
exec 3> >(sudo tee outputfile &>/dev/null)
echo output to the pipe like this >&3
echo etc. >&3
exec 3>&- # close it in the end
E, francamente, eu ainda acho que construir nomes de variáveis a partir de variáveis no script externo (como $${name}_E
) é um pouco feio, e provavelmente deve ser substituído por um Arrayassociativo .
Heredocs sempre terminam com caracteres de nova linha, mas você pode simplesmente remover isso. A maneira mais fácil que eu sei é com o programa head
:
head -c -1 <<EOF | sudo tee file > /dev/null
my
heredoc
content
EOF