Come eseguire l'eco dei comandi in uno script di shell bash, ma non eseguirli?


11

C'è un modo per eseguire uno script di shell con l'eco dei comandi ma senza eseguirli?

Diciamo che ho lo script che rimuove un file il cui nome è memorizzato in una variabile:

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

L'aggiunta set -vripeterà i seguenti comandi prima dell'esecuzione:

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

Ora, voglio vedere il flusso di questo script senza effettivamente rimuovere il file. IOW, voglio prevenire qualsiasi effetto sull'ambiente esterno e sul filesystem. È possibile?

Potrei avvolgere tutti i comandi con un echocomando, ma è stancante per un lungo script.


Non sono un esperto di scripting bash, ma se lo scrivessi con un altro linguaggio di programmazione, memorizzerei tutti i comandi in un array. in questo modo dovrebbe essere facile eseguire il ciclo continuo o eseguire i comandi o stampare il comando.
hugo der hungrige,

Risposte:


8

Non c'è modo di scorrere uno script per vedere come verrebbe eseguito senza farlo. Nel tuo esempio, non ci sono ifdichiarazioni o loop. Ma negli script reali, ci sono spesso molte dichiarazioni condizionali. Quale ramo verrà preso dipenderà spesso da ciò che è accaduto quando la shell ha eseguito il comando precedente. Se non esegue il comando, la shell non ha modo di sapere quale output avrebbe generato o quale sarebbe stato il codice di ritorno, da cui potrebbe dipendere il successivo ramo condizionale o istruzione di assegnazione.

Se il punto è che ti piacerebbe esaminare attentamente uno script e sapere cosa fa prima di eseguirlo, non è una cattiva idea. Ma realisticamente, il modo migliore per farlo è semplicemente sfogliando il file con lesso vio qualcosa di simile.

aggiunto

Se stai sviluppando uno script e vuoi esaminarlo per la prima volta, testando la logica ma in realtà non stai facendo alcun danno se hai un bug, la soluzione che sono spesso in grado di usare è modificare solo le affermazioni che potrebbero arrecare danni incollando una echosul davanti.

Questo spesso funziona con gli script tipici della vita reale perché (a) generare gli elenchi di elementi su cui ripeterai o il valore a cui imposterai una variabile spesso può essere generato senza cambiare il filesystem e (b) di solito è sufficiente per supponiamo che se avessi eseguito il comando, avrebbe avuto successo.


Grazie. Mi sorprenderebbe se ci fosse un modo, proprio per il motivo che hai citato, ma ho deciso di provarlo comunque. La ragione di ciò è che sto sviluppando uno script che sposta i file su molte macchine in una rete ed esegue alcune azioni sugli host remoti. Mi piacerebbe vedere un flusso dello script prima di eseguire effettivamente le modifiche al filesystem. Sarebbe altrettanto noioso esaminare tutte le macchine remote per correggere gli errori dei file ...
yap

1
Un'aggiunta: per scorrere lo script, è possibile avviare lo script con il trap read debugquale eseguirà una lettura dopo ogni riga eseguita, quindi è possibile procedere lentamente con Invio (questo è utile se si dispone di uno script davvero lungo e si desidera testare per la prima volta).
netigger

8

Penso che dovrai eco - tuttavia se metti il ​​comando in una variabile puoi accenderlo e spegnerlo. Inoltre, il comando può essere una funzione e sofisticato quanto vuoi.

#!/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


Ho richiesto le virgolette nei comandi echo / non-echo, e poi ho dovuto usare D=evalla parte live. Ma bella risposta!
Jasper

5

Puoi tracciare il flusso usando l'opzione -x per bash, ma questo eseguirà comunque i comandi.

Il meglio che puoi fare è semplicemente inserire l'eco o commentare i comandi che hanno effetti esterni come l'rm. Almeno non dovresti cambiare ogni riga.


Grazie. Ho citato questa opzione nella mia domanda, ma non risolve davvero il mio problema.

Scusa, pensavo volessi dire riecheggiare ogni riga, -x lo ridurrebbe a pochi comandi e ti mostrerebbe le valutazioni.
Parkydr,

4

Non conosco alcun metodo particolare per l'esecuzione a secco, ma possiamo usare alcune precauzioni per comprendere uno script sconosciuto.

  1. Utilizzare un ambiente chroot per eseguire lo script di debug. Funzionerà come sandbox e fornirà protezione contro l'eliminazione / modifica dei file di sistema principali.
  2. Utilizzare bash -n <script>per il controllo della sintassi . Dal manuale di 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. Leggi la sceneggiatura almeno una volta. È possibile utilizzare l'istruzione echo per il debug come indicato nella risposta dall'utente191016 .
    • Cerca codici sospetti o soggetti a pericoli.
    • ad es. relativi a rm, comandi che influenzano / dev / sda ecc.
  2. Cerca sempre di eseguire gli script come utente normale, evita di eseguire script sconosciuti come root.
  3. È possibile definire un alias per creare un comando in grado di modificare i file come interattivo all'inizio dello script Esempio alias rm="rm -i" alias cp="cp -i" alias mv="mv -i" Per gli editor di stream come sed sed -i(-i modifica il file in posizione senza -i esegue una corsa a secco per sed, consultare la pagina man per i dettagli) È possibile può copiare il comando completo ed eseguire. Appena prima del comando effettivo mostrerà l'output sullo schermo, quindi usa il comando per attendere che l'input dell'utente continui. Esempio sed -i <pattern> Sostituirlo con sed <pattern> read -p "Press any key..." sed -i <pattern>

Inoltre, si consiglia sempre di mantenere i punti di backup nel sistema in modo da poter ripristinare i dati di emergenza.


3

Fare set –n, o di aggiunta nal vostro esistente set –vcomando. Ma poiché ciò fa sì che la shell non valuti alcun comando, nemmeno ifo while, potresti non avere una visione troppo buona del flusso operativo.


Grazie. Questo è un buon inizio, ma come hai detto, non mi permette di vedere il flusso reale - dove nel mio vero script ho un ciclo su un elenco di host remoti.

3

Ecco un piccolo costrutto che mi piace usare:

#!/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

2

Se si desidera impedire che si verifichino modifiche, è possibile eseguire lo script come utente senza privilegi:

sudo -u nobody ./scr.sh

Nel tuo esempio, questo verrà eseguito FN="filename"come al solito. Anche se tecnicamente esegue anche il comando rm -f ${FN}, non accadrà nulla se nessuno non dispone delle autorizzazioni necessarie per eliminare il file.

Naturalmente, ciò causerà problemi con il flusso di lavoro condizionale. Il fatto che il rmcomando non sia riuscito potrebbe influire su ulteriori parti dello script.


Cose che non capiremo mai: perché il root è necessario per funzionare come nessuno ...
mjohnsonengr

L'utente "nobody" non è specifico per il sistema operativo, ma è possibile aggiungere una voce nel file sudoers che consenta sudo senza password per "nobody".
Dennis,

Non so. Sembra che lo script sarebbe terminato a causa di un errore o di un altro prima che finisse.
Edward Falk,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.