Script bash - contenu variable comme commande à exécuter

159

J'ai un script Perl qui me donne une liste définie de nombres aléatoires qui correspondent aux lignes d'un fichier. Ensuite, je veux extraire ces lignes du fichier en utilisant sed.

#!/bin/bash
count=$(cat last_queries.txt | wc -l)
var=$(perl test.pl test2 $count)

La variable varretourne une sortie comme: cat last_queries.txt | sed -n '12p;500p;700p'. Le problème est que je ne peux pas exécuter cette dernière commande. J'ai essayé avec $var, mais la sortie n'est pas correcte (si je lance manuellement la commande, cela fonctionne bien, donc pas de problème). Quelle est la bonne façon de procéder?

PS: Bien sûr, je pourrais faire tout le travail en Perl, mais j'essaie d'apprendre de cette façon, car cela pourrait m'aider dans d'autres situations.

Barata
la source

Réponses:

215

Il vous suffit de faire:

#!/bin/bash
count=$(cat last_queries.txt | wc -l)
$(perl test.pl test2 $count)

Cependant, si vous souhaitez appeler votre commande Perl plus tard, et c'est pourquoi vous souhaitez l'assigner à une variable, alors:

#!/bin/bash
count=$(cat last_queries.txt | wc -l)
var="perl test.pl test2 $count" # You need double quotes to get your $count value substituted.

...stuff...

eval $var

Selon l'aide de Bash:

~$ help eval
eval: eval [arg ...]
    Execute arguments as a shell command.

    Combine ARGs into a single string, use the result as input to the shell,
    and execute the resulting commands.

    Exit Status:
    Returns exit status of command or success if command is null.
hmontoliu
la source
176

Vous recherchez probablement eval $var.

August Karlstrom
la source
3
Cela a fonctionné en cas d' $($cmd))échec. Il dit toujours que la commande n'a pas été trouvée. Merci!
CMCDragonkai
2
line=$((${RANDOM} % $(wc -l < /etc/passwd)))
sed -n "${line}p" /etc/passwd

juste avec votre fichier à la place.

Dans cet exemple, j'ai utilisé le fichier / etc / password, en utilisant la variable spéciale ${RANDOM}(que j'ai apprise ici), et l' sedexpression que vous aviez, la seule différence est que j'utilise des guillemets doubles au lieu de simples pour permettre l'expansion de la variable.

nhed
la source
2

Dans le cas où vous avez plusieurs variables contenant les arguments d'une commande que vous exécutez, et pas seulement une seule chaîne, vous ne devez pas utiliser eval directement, car cela échouera dans le cas suivant:

function echo_arguments() {
  echo "Argument 1: $1"
  echo "Argument 2: $2"
  echo "Argument 3: $3"
  echo "Argument 4: $4"
}

# Note we are passing 3 arguments to `echo_arguments`, not 4
eval echo_arguments arg1 arg2 "Some arg"

Résultat:

Argument 1: arg1
Argument 2: arg2
Argument 3: Some
Argument 4: arg

Notez que même si "Some arg" a été passé comme argument unique, evallisez-le comme deux.

Au lieu de cela, vous pouvez simplement utiliser la chaîne comme commande elle-même:

# The regular bash eval works by jamming all its arguments into a string then
# evaluating the string. This function treats its arguments as individual
# arguments to be passed to the command being run.
function eval_command() {
  "$@";
}

Notez la différence entre la sortie de evalet la nouvelle eval_commandfonction:

eval_command echo_arguments arg1 arg2 "Some arg"

Résultat:

Argument 1: arg1
Argument 2: arg2
Argument 3: Some arg
Argument 4:
Ajedi32
la source
1
Pour éviter l'évaluation de chaque élément après l' espace, comme dans votre premier exemple avec eval, l' envelopper avec des guillemets simples: eval 'echo_arguments arg1 arg2 "Some arg"'. Ensuite, la sortie sera comme dans votre deuxième exemple.
Noam Manos