web-dev-qa-db-fra.com

Définir la variable dans le shell actuel à partir de awk

Est-il possible de définir une variable dans mon shell actuel à partir de awk?

Je voudrais faire un traitement sur un fichier et imprimer des données; étant donné que je lirai l'intégralité du fichier, j'aimerais enregistrer le nombre de lignes - dans ce cas, FNR.

Cela arrive mais je n'arrive pas à trouver le moyen de définir une variable Shell avec la valeur FNR; sinon, je devrais lire la FNR de mon fichier de sortie pour définir, par exemple num_lines, avec la valeur FNR.

J'ai essayé quelques combinaisons en utilisant awk 'END{system(...)}', mais je n'ai pas réussi à le faire fonctionner. Tout moyen de contourner ça? 

17
Rubens
$ echo "$var"

$ declare $( awk 'BEGIN{print "var=17"}' )
$ echo "$var"
17

Voici pourquoi vous devriez utiliser declare au lieu de eval:

$ eval $( awk 'BEGIN{print "echo \"removing all of your files, ha ha ha....\""}' )
removing all of your files, ha ha ha....

$ declare $( awk 'BEGIN{print "echo \"removing all of your files\""}' )
bash: declare: `"removing': not a valid identifier
bash: declare: `files"': not a valid identifier

Notez que dans le premier cas, eval exécute toutes les impressions de chaîne awk, ce qui pourrait accidentellement être une très mauvaise chose!

22
Ed Morton

Voici un autre moyen.

Ceci est particulièrement utile lorsque vous avez les valeurs de vos variables dans une variable single et que vous souhaitez les séparer. Par exemple, vous avez une liste de valeurs d'une seule ligne dans une base de données à partir de laquelle vous souhaitez créer des variables.

val="hello|beautiful|world" # assume this string comes from a database query
read a b c <<< $( echo ${val} | awk -F"|" '{print $1" "$2" "$3}' )

echo $a #hello
echo $b #beautiful
echo $c #world

Nous avons besoin de la 'chaîne ici', c'est-à-dire <<< dans ce cas, car la commande de lecture ne lit pas à partir d'un tube, mais à partir de stdin

19
Nerrve

Vous ne pouvez pas exporter de variables d'un sous-shell vers son shell parent. Vous avez cependant d'autres choix, notamment:

  1. Effectuez une autre passe du fichier en utilisant AWK pour compter les enregistrements et utilisez la substitution de commande pour capturer le résultat. Par exemple:

    FNR=$(awk 'END {print FNR}' filename)
    
  2. ImprimezFNRdans le sous-shell et analysez le résultat dans votre autre processus.
  3. SiFNRest égal au nombre de lignes, vous pouvez appeler wc -l < filename pour obtenir votre nombre.
4
Todd A. Jacobs

Un avertissement pour toute personne essayant d’utiliser déclare comme suggéré par plusieurs réponses.

eval n'a pas ce problème.

Si le awk (ou une autre expression) fourni pour déclarer les résultats dans une chaîne vide, declare déclarera l'environnement actuel . Ce n'est certainement pas ce que vous voudriez.

par exemple: si votre motif awk n'existe pas dans l'entrée, vous n'imprimerez jamais de sortie, ce qui entraînera un comportement inattendu.

Un exemple de ceci ....

 unset var
 var=99
 declare $( echo "foobar" | awk '/fail/ {print "var=17"}' )
 echo "var=$var"
var=99
The current environment as seen by declare is printed
and $var is not changed

Une modification mineure pour stocker la valeur à définir dans une variable awk et l’imprimer à la fin résout ce problème ....

 unset var
 var=99
 declare $( echo "foobar" | awk '/fail/ {tmp="17"} END {print "var="tmp}' )
 echo "var=$var"
var=
This time $var is unset ie: set to the null string var=''
and there is no unwanted output.

Pour montrer ce travail avec un motif correspondant

 unset var
 var=99
 declare $( echo "foobar" | awk '/foo/ {tmp="17"} END {print "var="tmp}' )
 echo "var=$var"
var=
This time $var is unset ie: set to the null string var=''
and there is no unwanted output.
3
sbts

Faites awk imprimer la déclaration de mission:

MYVAR=NewValue

Ensuite, dans votre script Shell, eval la sortie de votre script awk:

eval $(awk ....)
# then use $MYVAR

EDIT: les utilisateurs recommandent d'utiliser declare au lieu de eval, pour être légèrement moins sujet aux erreurs si autre chose que l'affectation est imprimée par le script interne. C'est seulement bash, mais ça va quand le shell est bash et que le script a #!/bin/bash, déclarant correctement cette dépendance.

La variante eval $(...) est largement utilisée, les programmes existants générant une sortie appropriée pour eval mais pas pour declare (lesspipe est un exemple); c'est pourquoi il est important de le comprendre, et la variante uniquement bash est "trop ​​localisée".

1
Anton Kovalenko

Pour synthétiser tout ce qui a été fait jusqu'ici, je vais partager ce que je trouve utile pour définir une variable d'environnement Shell à partir d'un script qui lit un fichier d'une ligne à l'aide de awk. De toute évidence, un /pattern/ pourrait être utilisé à la place de NR==1 pour trouver la variable requise.

# export a variable from a script (such as in a .dotfile)
declare $( awk 'NR==1 {tmp=$1} END {print "Shell_VAR=" tmp}' /path/to/file )
export Shell_VAR

Cela évitera une sortie massive de variables si une commande declare est émise sans argument, ainsi que les risques de sécurité d'une eval aveugle.

1
Merlin

echo "Premier argument: $ 1" pour ((i = 0; i <$ 1; i ++)); do echo "inside" echo "Welcome $ i times." cat man.xml | awk '{x [NR] = $ 0} FIN {pour (i = 2; i <= NR; i ++) {si (x [i] ~ //) {x [i + 1] = "' $ i '" } print x [i]}} '> $ i.xml done echo "compleated"

0
Hari Prassana