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?
$ 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!
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
Vous ne pouvez pas exporter de variables d'un sous-shell vers son shell parent. Vous avez cependant d'autres choix, notamment:
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)
wc -l < filename
pour obtenir votre nombre.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.
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".
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.
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"