Como ecoar comandos em um script shell bash, mas não executá-los?

11

Existe uma maneira de executar um script de shell ecoando os comandos, mas sem executá-los?

Digamos que eu tenha um script removendo um arquivo cujo nome esteja armazenado em uma variável:

#!/bin/bash
set -v
FN="filename"
rm -f ${FN}

A adição set -vfará eco dos seguintes comandos antes da execução:

$ ./scr.sh
FN="filename"
rm -f ${FN}

Agora, quero ver o fluxo desse script sem remover o arquivo. IOW, quero impedir qualquer efeito no ambiente externo e no sistema de arquivos. Isso é possível?

Eu poderia agrupar todos os comandos com um echocomando, mas é cansativo para um script longo.

ysap
fonte
Eu não sou especialista em scripts bash, mas se eu escrever isso com outra linguagem de programação, armazenarei todos os comandos em uma matriz. Dessa forma, deve ser fácil percorrer e executar os comandos ou imprimir o resultado.
Hugo der hungrige 16/03/14

Respostas:

8

Não há como percorrer um script para ver como ele seria executado sem realmente fazer isso. No seu exemplo, não há ifinstruções ou loops. Mas em scripts reais, muitas vezes há muitas instruções condicionais. O ramo que será obtido dependerá frequentemente do que aconteceu quando o shell executou o comando anterior. Se ele não executar o comando, não há como o shell saber qual saída geraria ou qual seria o código de retorno, do qual a próxima ramificação condicional ou instrução de atribuição pode depender.

Se a questão é que você deseja examinar um script e saber o que ele faz antes de executá-lo, isso não é uma má idéia. Mas, realisticamente, a melhor maneira de fazer isso é apenas navegando no arquivo com lessou viou algo semelhante.

Adicionado

Se você está desenvolvendo um script e deseja percorrê-lo pela primeira vez, testando a lógica, mas sem causar nenhum dano se tiver um bug, a solução que geralmente posso usar é modificar apenas as declarações que poderiam causar algum dano colando um echona frente.

Isso geralmente funciona em scripts típicos da vida real porque (a) gerar as listas de itens sobre os quais você iterará ou o valor para o qual você definirá uma variável geralmente pode ser gerado sem alterar o sistema de arquivos e (b) geralmente é suficiente para suponha que se você executasse o comando, ele seria bem-sucedido.

Nicole Hamilton
fonte
Obrigado. Me surpreenderia se houvesse uma maneira, exatamente devido ao motivo que você mencionou, mas decidi tentar de qualquer maneira. A razão para isso é que estou desenvolvendo um script que move arquivos por várias máquinas em uma rede e executa algumas ações nos hosts remotos. Eu gostaria de ver um fluxo do script antes de realmente confirmar as alterações no (s) sistema (s) de arquivos. Seria igualmente tedioso
revisar
11
Uma adição: Para percorrer o script, você pode iniciar o script com o trap read debugqual fará uma leitura após cada linha executada e, em seguida, percorrê-lo lentamente com enter (isso é útil se você tiver um script muito longo e quiser testar pela primeira vez).
netigger
8

Eu acho que você terá que repetir - no entanto, se você colocar o comando em uma variável, poderá ativá-lo e desativá-lo. Além disso, o comando pode ser uma função e tão sofisticado quanto você desejar.

#!/bin/bash
echo 'Debug'
  D=echo
  :>| testy
  ls -l testy
  $D rm -f testy
  ls -l testy
echo $'\n\nLive'
  D=
  :>| testy
  ls -l testy
  $D rm -f testy
  ls -l testy

!$ > ./conditional.sh
Debug
-rw-rw-r-- 1 nobody nobody 0 2013-01-18 15:28 testy
rm -f testy
-rw-rw-r-- 1 nobody nobody 0 2013-01-18 15:28 testy

Live -rw-rw-r-- 1 nobody nobody 0 2013-01-18 15:28 testy ls: cannot access testy: No such file or directory

user191016
fonte
Eu exigi aspas nos comandos echo / don't-eco e tive que usar D=evalna parte ao vivo. Mas boa resposta!
Jasper
5

Você pode rastrear o fluxo usando a opção -x para bash, mas isso ainda executaria os comandos.

O melhor que você pode fazer é colocar eco ou comentar os comandos que têm efeitos externos, como o rm. Pelo menos você não precisaria mudar todas as linhas.

parkydr
fonte
Obrigado. Mencionei essa opção na minha pergunta, mas isso realmente não resolve o meu problema.
ysap
Desculpe, pensei que você quisesse ecoar cada linha, -x reduziria isso a alguns comandos e mostraria as avaliações.
parkydr
4

Não conheço nenhum método específico para execução a seco, mas podemos usar algumas precauções para entender um script desconhecido.

  1. Use um ambiente chroot para executar seu script de depuração. Ele atuará como uma caixa de proteção e fornecerá proteção contra a exclusão / modificação de arquivos principais do sistema.
  2. Use bash -n <script>para verificação de sintaxe . No manual do gnu bash https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html

-n Read commands but do not execute them; this may be used to check a script for syntax errors. This option is ignored by interactive shells.

  1. Leia o script pelo menos uma vez. Você pode usar a instrução echo para depuração, conforme mencionado na resposta por user191016 .
    • Procure código suspeito ou sujeito a perigo.
    • por exemplo, relacionados à rm, comandos que afetam / dev / sda etc.
  2. Sempre tente executar scripts como usuário normal, evite executar scripts desconhecidos como raiz.
  3. Você pode definir um alias para tornar o comando que pode modificar os arquivos como interativos no início do seu script. Exemplo alias rm="rm -i" alias cp="cp -i" alias mv="mv -i" Para editores de fluxo como sed sed -i(-i modifica o arquivo no local sem -i, ele executa uma execução a seco para sed, consulte a página de manual para obter detalhes) pode copiar o comando completo e executar. Antes do comando atual, ele mostra a saída na tela e, em seguida, use o comando para aguardar a entrada do usuário continuar. Exemplo sed -i <pattern> Substitua-o por sed <pattern> read -p "Press any key..." sed -i <pattern>

Também é sempre recomendável manter pontos de backup em seu sistema para que, em caso de emergência, os dados possam ser restaurados.

Rohit Raj Mishra
fonte
3

Faça set –nou acrescente nao seu set –vcomando existente . Mas como isso faz com que o shell não avalie nenhum comando, nem mesmo ifou while, talvez você não tenha uma visão muito boa do fluxo operacional.

Scott
fonte
Obrigado. Este é um bom começo, mas, como você mencionou, não me permite ver o fluxo real - onde no meu script real eu tenho um loop sobre uma lista de hosts remotos.
usar o seguinte comando
3

Aqui está uma pequena construção que eu gosto de usar:

#!/bin/sh

verbose=false
really=true

# parse arguments
while [ $# -ge 1 ]
do
  case "$1" in
    -v) verbose=true ;;
    -n) really=false; verbose=true ;;
  esac
  shift
done

doCmd() {
  if $verbose; then echo "$@"; fi
  if $really; then "$@"; fi
}

doCmd make foo
doCmd rm -rf /tmp/installdir
doCmd mkdir /tmp/installdir
doCmd whatever
doCmd blah blah
Edward Falk
fonte
2

Se você deseja impedir que modificações ocorram, é possível executar o script como usuário sem privilégios:

sudo -u nobody ./scr.sh

No seu exemplo, isso será executado FN="filename"como de costume. Embora tecnicamente execute o comando rm -f ${FN}também, nada acontecerá se ninguém não tiver as permissões necessárias para excluir o arquivo.

Obviamente, isso causará problemas no fluxo de trabalho condicional. O fato de o rmcomando falhar pode afetar outras partes do script.

Dennis
fonte
Coisas que nunca vai entender: Por root é necessária para executar como ninguém ...
mjohnsonengr
O usuário "ninguém" não é relevante para o sistema operacional, mas você pode adicionar uma entrada no arquivo sudoers que permita sudo sem senha para "ninguém".
Dennis
Não sei. Parece que o script seria encerrado devido a algum erro ou outro antes de terminar.
Edward Falk