Estou escrevendo um enorme script 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 gera um código (se houver, por exemplo, 2 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 em linha de código que eu produzo com os heredocs, já que os acho muito melhores para escrever e manter. Por exemplo, após o código superior, 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
Portanto, 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 um heredoc se comportar de maneira semelhante echo -ne
sem o símbolo de fim de linha?
sudo
de um script, está fazendo errado: execute o script inteiro como root!sudo -u USERNAME
em vez disso, consulte Como executo um comando 'sudo' dentro de um script? .sudo
sem nome de usuário pede a senha, a menos que você a tenha digitado, há um atraso. É ainda pior se você não executar o script em um terminal, nem poderá ver a consulta da senha e ela simplesmente não funcionará. Asudo -u
abordagem não apresenta nenhum desses problemas.Respostas:
Não, o heredoc sempre termina em uma nova linha. Mas você ainda pode remover a última nova linha, por exemplo, com Perl:
-p
lê a entrada linha por linha, executa o código especificado em-e
e imprime a linha (possivelmente modificada)fonte
A resposta curta é que heredoc e herestrings são construídos dessa maneira, então não - aqui-doc e herestring sempre adicionam uma nova linha à direita e não há opção ou maneira nativa de desabilitá-la (talvez haja versões futuras do bash?).
No entanto, uma maneira de abordá-lo por meio de somente bash seria ler o que o heredoc fornece por meio do
while IFS= read -r
método padrão , mas adicionar um atraso e imprimir a última linhaprintf
sem a nova linha à direita. Aqui está o que se poderia fazer com somente bash:O que você vê aqui é o loop while usual com
IFS= read -r line
abordagem, no entanto, cada linha é armazenada em uma variável e, portanto, atrasada (então pulamos a impressão da primeira linha, a armazenamos e começamos a imprimir somente quando lemos a segunda linha). Dessa forma, podemos capturar a última linha e, quando na próxima iteraçãoread
retornar o status de saída 1, é quando imprimimos a última linha sem a nova linha viaprintf
. Verbose? sim. Mas funciona:Observe o
$
caractere de prompt sendo empurrado para a frente, pois não há nova linha. Como um bônus, esta solução é portátil e POSIX-ish, assim que deve funcionar emksh
edash
bem.fonte
Eu recomendo que você tente uma abordagem diferente. Em vez de reunir seu script gerado a partir de várias instruções de eco e heredocs. Eu sugiro que você tente usar um único heredoc.
Você pode usar expansão variável e substituição de comando dentro de um heredoc. Como neste exemplo:
Acho que isso muitas vezes leva a resultados finais muito mais legíveis do que produzir a saída peça por peça.
Também parece que você esqueceu a
#!
linha no início de seus scripts. A#!
linha é obrigatória em qualquer script formatado corretamente. Tentar executar um script sem a#!
linha funcionará apenas se você o chamar de um shell que contorna scripts mal formatados e, mesmo nesse caso, pode acabar sendo interpretado por um shell diferente do pretendido.fonte
#!
mas meu bloco de código é apenas um trecho de um script de 2000 linhas;) Não vejo agora como sua sugestão resolve meu problema ao gerar uma linha de código em um loop while ...$( ...command...)
dentro de um heredoc, para inserir a saída desses comandos em linha naquele ponto no heredoc; (3) O Bash possui variáveis de matriz, que você pode expandir em linha e usar substituições para adicionar itens no início / fim, se necessário. Juntos, eles tornam a sugestão de Kasperd muito mais poderosa (e seu script potencialmente muito mais legível).Os heredocs sempre terminam com caracteres de nova linha, mas você pode simplesmente removê-lo. A maneira mais fácil que eu conheço é com o
head
programa:fonte
-c
também leva valores negativos! Como se isso ainda mais do que apearl
soluçãoVocê pode remover as novas linhas da maneira que desejar, a canalização
tr
provavelmente seria a mais simples. Isso removeria todas as novas linhas, é claro.Porém, a instruçã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
produzindo
Construí-lo em um loop ainda torna feio, no entanto. O
|| 0
que há, naturalmente, de modo que nós não precisa caso especial a primeira ou a última linha.Além disso, você tem isso
| sudo tee ...
em todas as saídas. Acho que poderíamos nos livrar disso abrindo um redirecionamento apenas uma vez (com substituição de processo) e usando isso para a impressão posterior:E, francamente, ainda acho que a criação de nomes de variáveis a partir de variáveis no script externo (assim
\$${name}_E
) é um pouco feia e provavelmente deve ser substituída por uma matriz associativa .fonte