web-dev-qa-db-fra.com

Comment stocker une commande dans une variable dans un script Shell?

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

J'ai un script simple comme suit:

command="ls";
echo "Command: $command"; #Output is: Command: ls

b=`$command`;
echo $b; #Output is: public_html REV test... (command worked successfully)

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

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

La sortie est:

Command: ls | grep -c '^'
ls: cannot access |: No such file or directory
ls: cannot access grep: No such file or directory
ls: cannot access '^': No such file or directory

Avez-vous une idée de la façon dont je pourrais stocker une telle commande (avec des tubes/plusieurs commandes) dans une variable pour une utilisation ultérieure?

94
Benjamin

Utilisez eval:

x="ls | wc"
eval "$x"
y=$(eval "$x")
echo "$y"
128
Erik

Ne pas utilisez eval! Il y a un risque majeur d’introduction de l’exécution de code arbitraire.

BashFAQ-5 - J'essaie de mettre une commande dans une variable, mais les cas complexes échouent toujours.

Placez-le dans un tableau et développez tous les mots avec des guillemets doubles "${arr[@]}" to not laissez le IFS diviser les mots en raison de fractionnement de mots .

cmdArgs=()
cmdArgs=('date' '+%H:%M:%S')

et voir le contenu du tableau à l'intérieur. Le declare -p vous permet de voir le contenu du tableau à l'intérieur avec chaque paramètre de commande dans des index distincts. Si un tel argument contient des espaces, la citation à l'intérieur lors de l'ajout au tableau l'empêchera d'être scindée en raison de la division de Word.

declare -p cmdArgs
declare -a cmdArgs='([0]="date" [1]="+%H:%M:%S")'

et exécuter les commandes en tant que

"${cmdArgs[@]}"
23:15:18

(ou) utilisez tout simplement une fonction bash pour exécuter la commande,

cmd() {
   date '+%H:%M:%S'
}

et appelez la fonction juste

cmd

POSIX sh n'a pas de tableaux, vous pouvez donc créer une liste d'éléments dans les paramètres de position. Voici un moyen POSIX sh d'exécuter un programme de messagerie

# POSIX sh
# Usage: sendto subject address [address ...]
sendto() {
    subject=$1
    shift
    first=1
    for addr; do
        if [ "$first" = 1 ]; then set --; first=0; fi
        set -- "$@" --recipient="$addr"
    done
    if [ "$first" = 1 ]; then
        echo "usage: sendto subject address [address ...]"
        return 1
    fi
    MailTool --subject="$subject" "$@"
}

Notez que cette approche ne peut gérer que des commandes simples sans redirections. Il ne peut pas gérer les redirections, les pipelines, les boucles for/while, les instructions if, etc.

32
Inian
var=$(echo "asdf")
echo $var
# => asdf

En utilisant cette méthode, la commande est immédiatement évaluée et sa valeur de retour est stockée.

stored_date=$(date)
echo $stored_date
# => Thu Jan 15 10:57:16 EST 2015
# (wait a few seconds)
echo $stored_date
# => Thu Jan 15 10:57:16 EST 2015

Même avec backtick

stored_date=`date`
echo $stored_date
# => Thu Jan 15 11:02:19 EST 2015
# (wait a few seconds)
echo $stored_date
# => Thu Jan 15 11:02:19 EST 2015

Utiliser eval dans la $(...) ne le fera pas évaluer plus tard

stored_date=$(eval "date")
echo $stored_date
# => Thu Jan 15 11:05:30 EST 2015
# (wait a few seconds)
echo $stored_date
# => Thu Jan 15 11:05:30 EST 2015

En utilisant eval, il est évalué lorsque eval est utilisé

stored_date="date" # < storing the command itself
echo $(eval "$stored_date")
# => Thu Jan 15 11:07:05 EST 2015
# (wait a few seconds)
echo $(eval "$stored_date")
# => Thu Jan 15 11:07:16 EST 2015
#                     ^^ Time changed

Dans l'exemple ci-dessus, si vous devez exécuter une commande avec des arguments, placez-les dans la chaîne que vous stockez.

stored_date="date -u"
# ...

Pour les scripts bash, cela est rarement pertinent, mais une dernière note. Soyez prudent avec eval. N'évaluez que les chaînes que vous contrôlez, jamais celles provenant d'un utilisateur non fiable ou construites à partir d'une entrée utilisateur non fiable.

  • Merci à @CharlesDuffy de m'avoir rappelé de citer la commande!
22
Nate