195 votes

Comment puis-je stocker une commande dans une variable dans un script shell?

Je voudrais stocker une commande à utiliser ultérieurement dans une variable (pas la sortie de la commande, mais la commande elle-même).

J'ai un script simple comme suit:

command="ls";
echo "Commande: $command"; #La sortie est: Commande: ls

b=`$command`;
echo $b; #La sortie est public_html REV test... (la commande a fonctionné avec succès)

Cependant, lorsque j'essaie quelque chose de plus compliqué, cela échoue. Par exemple, si je fais

command="ls | grep -c '^'";

La sortie est:

Commande: ls | grep -c '^'
ls: ne peut pas accéder à |: Aucun fichier ou dossier de ce type
ls: ne peut pas accéder à grep: Aucun fichier ou dossier de ce type
ls: ne peut pas accéder à '^': Aucun fichier ou dossier de ce type

Comment pourrais-je stocker une telle commande (avec des pipes/des commandes multiples) dans une variable pour une utilisation ultérieure?

15 votes

Utilisez une fonction!

0voto

Dudi Boy Points 439

J'ai rencontré ce problème avec la commande suivante :

awk '{printf "%s[%s]\n", $1, $3}' "input.txt"

Je dois construire cette commande de manière dynamique :

Le nom du fichier cible input.txt est dynamique et peut contenir des espaces.

Le script awk à l'intérieur des accolades {} printf "%s[%s]\n", $1, $3 est dynamique.

Défi :

  1. Évitez une logique d'échappement de guillemets extensive s'il y a de nombreux " à l'intérieur du script awk.
  2. Évitez l'expansion de paramètres pour chaque variable de champ $.

Les solutions ci-dessous avec la commande eval et les tableaux associatifs ne fonctionnent pas. En raison des expansions de variables et de guillemets de bash.

Solution :

Construisez la variable de bash de manière dynamique, évitez les expansions de bash, utilisez le modèle de printf.

 # variables dynamiques, les valeurs changent au moment de l'exécution.
 input="input file 1.txt"
 awk_script='printf "%s[%s]\n" ,$1 ,$3'

 # modèle de commande statique, prévenant les échappements de guillemets doubles et évite les expansions de variables.
 awk_command=$(printf "awk '{%s}' \"%s\"\n" "$awk_script" "$input")
 echo "awk_command=$awk_command"

 awk_command=awk '{printf "%s[%s]\n" ,$1 ,$3}' "input file 1.txt"

Exécution de la commande dynamique :

bash -c "$awk_command"

Alternative qui fonctionne également

bash << $awk_command

-1voto

Mark Points 49079

J'ai essayé différentes méthodes :

printexec() {
  printf -- "\033[1;37m$\033[0m"
  printf -- " %q" "$@"
  printf -- "\n"
  eval -- "$@"
  eval -- "$*"
  "$@"
  "$*"
}

Résultat :

$ printexec echo  -e "foo\n" bar
$ echo -e foo\\n bar
foon bar
foon bar
foo
 bar
bash: echo -e foo\n bar: command not found

Comme vous pouvez le voir, seul le troisième, "$@", a donné le bon résultat.

0 votes

Quelle est l'explication pour cela? Pourquoi seulement le troisième? Veuillez répondre en modifiant (changeant) votre réponse, pas ici dans les commentaires (sans "Édition :", "Mise à jour :", ou similaire - la réponse devrait apparaître comme si elle était écrite aujourd'hui).

0 votes

Je ne suis pas sûr que cela m'intéresse assez pour enquêter sur les subtilités de eval. A mon avis, l'un de ces deux aurait dû fonctionner.

-1voto

Azerty Points 1

Sois prudent en enregistrant une commande avec : X=$(Commande)

Celle-ci est toujours exécutée. Même avant d'être appelée. Pour vérifier et confirmer cela, vous pouvez faire :

echo test;
X=$(for ((c=0; c<=5; c++)); do
sleep 2;
done);
echo notez les 5 secondes écoulées

1 votes

Cela ne semble pas être une réponse à la question réelle ici, et devrait probablement être un commentaire à la place (voire même moins que cela).

0 votes

Que voulez-vous dire par "enregistrer une commande"? Pouvez-vous élaborer?

-1voto

Silentexpert Points 29
#!/bin/bash
#Note : ce script ne fonctionne que lorsque vous utilisez Bash. Donc, ne supprimez pas la première ligne.

TUNECOUNT=$(ifconfig |grep -c -o tune0) #Quelque commande avec "Grep".
echo $TUNECOUNT                         #Cela renverra 0 
                                    #si vous n'avez pas l'interface tune0.
                                    #Ou le compte des interfaces tune0 installées.

0 votes

Cela stocke la sortie de chaîne statique de la commande dans une variable, pas la commande elle-même.

0 votes

grep -c -o n'est pas entièrement portable; vous vous attendriez peut-être à ce qu'il renvoie le nombre réel d'occurrences de l'expression de recherche, mais au moins GNU grep ne le fait pas (c'est essentiellement équivalent à grep -c sans le -o).

0 votes

Le commentaire Bash-only est bizarre; il n'y a rien dans ce script simple qui ne soit compatible avec n'importe quel shell de la famille Bourne.

-2voto

Ivan Points 3650

Tout d'abord, il existe des fonctions pour cela. Mais si vous préférez les variables, alors votre tâche peut être effectuée de cette manière :

$ cmd=ls

$ $cmd # fonctionne
fichier  fichier2  test

$ cmd='ls | grep file'

$ $cmd # ne fonctionne pas
ls: ne peut accéder à '|': Aucun fichier ou dossier de ce type
ls: ne peut accéder à 'grep': Aucun fichier ou dossier de ce type
 fichier

$ bash -c $cmd # fonctionne
fichier  fichier2  test

$ bash -c "$cmd" # fonctionne également
fichier
fichier2

$ bash <<< $cmd
fichier
fichier2

$ bash <<< "$cmd"
fichier
fichier2

Ou via un fichier temporaire

$ tmp=$(mktemp)
$ echo "$cmd" > "$tmp"
$ chmod +x "$tmp"
$ "$tmp"
fichier
fichier2

$ rm "$tmp"

1 votes

Je suppose que beaucoup de gens n'ont pas remarqué la mention "Tout d'abord, il y a des fonctions pour cela" que vous avez mentionnée, qui est un bon pointeur dans la bonne direction à mon humble avis : "Les variables contiennent des données. Les fonctions contiennent du code"

0 votes

Votre bash -c $cmd et bash -c "$cmd" font deux choses TRÈS différentes! Essayez chaque manière avec cmd='echo "$(pwd)"; cd test2; echo "$(pwd)"' Pour comprendre pourquoi, faites 'bash -x -c $cmd'.

0 votes

Aussi: Les fonctions ne sont pas une solution, Elles peuvent être une alternative dans certains cas, mais vous devez construire la fonction! Si vous obtenez les morceaux de $cd comme une série de $1, $2, etc., amusez-vous à la transformer en une fonction, puis amusez-vous encore plus à ne pas utiliser eval pour l'utiliser dans un autre shell.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X