Comment faire écho aux commandes dans un script shell bash, mais pas les exécuter?

11

Existe-t-il un moyen d'exécuter un script shell en faisant écho aux commandes mais sans les exécuter réellement?

Disons que j'ai un script supprimant un fichier dont le nom est stocké dans une variable:

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

L'ajout set -vfera écho aux commandes suivantes avant l'exécution:

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

Maintenant, je veux voir le flux de ce script sans supprimer réellement le fichier. IOW, je veux empêcher tout effet sur l'environnement externe et le système de fichiers. Est-ce possible?

Je pourrais envelopper toutes les commandes avec une echocommande, mais c'est fatigant pour un long script.

ysap
la source
Je ne suis pas un expert en script bash, mais si j'écrivais cela avec un autre langage de programmation, je stockerais toutes les commandes dans un tableau. de cette façon, il devrait être facile de parcourir et d'exécuter les commandes ou d'imprimer.
hugo der hungrige

Réponses:

8

Il n'y a aucun moyen de parcourir un script pour voir comment il s'exécuterait sans le faire. Dans votre exemple, il n'y a ni ifinstructions ni boucles. Mais dans les vrais scripts, il y a souvent beaucoup d'instructions conditionnelles. La branche qui sera prise dépendra souvent de ce qui s'est passé lorsque le shell a exécuté la commande précédente. S'il n'exécute pas la commande, le shell n'a aucun moyen de savoir quelle sortie il aurait généré ou quel aurait été le code de retour, sur lequel la prochaine branche conditionnelle ou instruction d'affectation pourrait dépendre.

Si le fait est que vous souhaitez examiner un script et savoir ce qu'il fait avant de l'exécuter, ce n'est pas une mauvaise idée. Mais en réalité, la meilleure façon de le faire est de simplement parcourir le fichier avec lessou viou quelque chose de similaire.

Ajoutée

Si vous développez un script et que vous souhaitez le parcourir la première fois, tester la logique mais ne pas réellement endommager si vous avez un bug, la solution que je peux souvent utiliser est de modifier uniquement les déclarations qui pourraient causer des dommages en collant un echosur le devant.

Cela fonctionne souvent dans les scripts typiques de la vie réelle, car (a) la génération des listes d'éléments que vous allez parcourir ou la valeur à laquelle vous allez définir une variable peut souvent être générée sans changer le système de fichiers et (b) elle est généralement suffisante pour supposons que si vous exécutiez la commande, elle réussirait.

Nicole Hamilton
la source
Merci. Cela me surprendrait s'il y a un moyen, exactement pour la raison que vous avez mentionnée, mais j'ai quand même décidé de l'essayer. La raison en est que je développe un script qui déplace les fichiers sur plusieurs machines d'un réseau et effectue certaines actions sur les hôtes distants. Je voudrais voir un flux du script avant de valider les modifications du ou des systèmes de fichiers. Il serait tout aussi fastidieux de parcourir toutes les machines distantes pour corriger les erreurs de fichiers ...
ysap
1
Un ajout: pour parcourir le script, vous pouvez démarrer le script avec trap read debuglequel fera une lecture après chaque ligne exécutée, et vous pouvez ensuite le parcourir lentement avec enter (ceci est utile si vous avez un script vraiment long et que vous voulez tester pour la première fois).
netigger
8

Je pense que vous allez devoir faire écho - cependant si vous mettez la commande dans une variable, vous pouvez l'activer et la désactiver. De plus, la commande peut être une fonction aussi sophistiquée que vous le souhaitez.

#!/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
la source
J'ai demandé des guillemets dans les commandes echo / don't-echo, puis j'ai dû les utiliser D=evaldans la partie live. Mais belle réponse!
Jasper
5

Vous pouvez suivre le flux en utilisant l'option -x pour bash, mais cela exécuterait toujours les commandes.

Le mieux que vous puissiez faire est de simplement mettre en écho ou de commenter les commandes qui ont des effets externes comme le rm. Au moins, vous n'auriez pas à changer chaque ligne.

parkydr
la source
Merci. J'ai mentionné cette option dans ma question, mais cela ne résout pas vraiment mon problème.
ysap
Désolé, je pensais que vous vouliez faire écho à chaque ligne, -x réduirait cela à quelques commandes et vous montrerait les évaluations.
parkydr
4

Je ne connais pas de méthode particulière pour le dry run, mais nous pouvons utiliser quelques précautions pour comprendre un script inconnu.

  1. Utilisez un environnement chroot pour exécuter votre script de débogage. Il agira comme un bac à sable et fournira une protection contre la suppression / modification des fichiers système principaux.
  2. Utilisez bash -n <script>pour la vérification de la syntaxe . Depuis le manuel de 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. Lisez le script au moins une fois. Vous pouvez utiliser l'instruction echo pour le débogage comme mentionné dans la réponse de user191016 .
    • Recherchez les codes suspects ou sujets aux dangers.
    • par exemple liés à rm, aux commandes affectant / dev / sda etc.
  2. Essayez toujours d'exécuter des scripts en tant qu'utilisateur normal, évitez d'exécuter des scripts inconnus en tant que root.
  3. Vous pouvez définir un alias pour rendre la commande qui peut modifier des fichiers comme interactifs au début de votre script Exemple alias rm="rm -i" alias cp="cp -i" alias mv="mv -i" Pour les éditeurs de flux comme sed sed -i(-i modifie le fichier en place sans -i il fait un essai à sec pour sed, consultez la page de manuel pour plus de détails) Vous peut copier la commande complète et exécuter. Juste avant la commande réelle, il affichera la sortie à l'écran, puis utilisez la commande pour attendre que l'utilisateur continue. Exemple sed -i <pattern> Remplacez-le par sed <pattern> read -p "Press any key..." sed -i <pattern>

De plus, il est toujours suggéré de conserver des points de sauvegarde dans votre système afin qu'en cas d'urgence, les données puissent être restaurées.

Rohit Raj Mishra
la source
3

Faites set –nou ajoutez nà votre set –vcommande existante . Mais comme cela empêche le shell d'évaluer les commandes, même pas ifou while, vous risquez de ne pas avoir une vue trop précise du flux opérationnel.

Scott
la source
Merci. C'est un bon début, mais comme vous l'avez mentionné, cela ne me permet pas de voir le flux réel - où dans mon vrai script, j'ai une boucle sur une liste d'hôtes distants.
ysap
3

Voici une petite construction que j'aime utiliser:

#!/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
la source
2

Si vous souhaitez empêcher les modifications de se produire, vous pouvez exécuter le script en tant qu'utilisateur sans privilèges:

sudo -u nobody ./scr.sh

Dans votre exemple, cela s'exécutera FN="filename"comme d'habitude. Bien qu'il exécute techniquement la commande rm -f ${FN}également, rien ne se passera si personne n'a les autorisations nécessaires pour supprimer le fichier.

Bien sûr, cela entraînera des problèmes avec le workflow conditionnel. Le fait que la rmcommande ait échoué peut affecter d'autres parties du script.

Dennis
la source
Des choses que nous ne comprendrons jamais: pourquoi root doit fonctionner comme personne ...
mjohnsonengr
L'utilisateur "personne" n'est pas spécial pour le système d'exploitation, mais vous pouvez ajouter une entrée dans le fichier sudoers qui autorise le sudo sans mot de passe pour "personne".
Dennis
Je ne sais pas. Semble que le script se terminerait en raison d'une erreur ou d'une autre avant la fin.
Edward Falk