2009-12-25 3 views
33

Je souhaite exécuter la commande system dans un script awk et obtenir sa sortie stockée dans une variable. J'ai essayé de faire ceci, mais la sortie de la commande va toujours au shell et je ne suis pas capable de le capturer. Des idées sur la façon dont cela peut être fait?Affectation de la sortie de la commande système à la variable

Exemple:

$ date | awk --field-separator=! {$1 = system("strip $1"); /*more processing*/} 

doit appeler la commande du système strip et au lieu d'envoyer la sortie à la coquille, devrait affecter la sortie de retour à $1 pour plus de traitement. Rignt maintenant, il envoie la sortie à shell et attribue le retcode de la commande à $1.

+1

nit: La sortie ne va pas à la coquille, il va à la borne /console. Le shell ne lit aucun des résultats de ses enfants - ils partagent simplement des descripteurs de fichiers associés au même tty. –

Répondre

23

À calculer.

Nous utilisons Two-way I/O de awk

{ 
    "strip $1" |& getline $1 
} 

passe 1 $ à bande et la getline prend sortie de la bande de retour à 1

+1

Si vous devez appeler la même commande plusieurs fois, nous devons fermer la commande (http://www.staff.science.uu.nl/~oostr102/docs/nawk/nawk_26.html#SEC29) – mcoolive

49

$ Note: coPROcess est GNU awk spécifique. Quoi qu'il en soit une autre alternative est d'utiliser getline

cmd = "strip "$1 
while ((cmd | getline result) > 0) { 
    print result 
} 
close(cmd) 
+0

Merci. De cette façon, je peux enlever le & de ma réponse. On dirait plus cool. Mais je n'écris que pour Linux, donc l'indisponibilité de gawk ne devrait pas être un problème? – Sahas

+0

oui, ne devrait pas être un problème. encore vous devriez vérifier la documentation et voir si coprocess est seulement disponible dans certaine version de gawk. Je ne me souviens plus de ma tête – ghostdog74

+0

A partir de la version 3.1. RedHat a 3.1.5. De toute façon je vais utiliser comme vous l'avez suggéré, sauf si je veux envoyer quelque chose à stdin de la commande, auquel cas coprocess est utile. – Sahas

5
gawk '{dt=substr($4,2,11); gsub(/\//," ",dt); "date -d \""dt"\" +%s"|getline ts; print ts}' 
+13

Si vous publiez des réponses, vous devez expliquer les différentes parties (ce que vous avez fait et pourquoi cela fonctionne). Pour que les autres puissent apprendre de votre réponse. Pour certaines personnes, cette ligne s'expliquerait elle-même. Mais pour d'autres, c'est difficile de suivre ce que vous avez fait exactement. –

16

Pour exécuter une commande de système awk vous pouvez utiliser system() ou cmd | getline.

Je préfère cmd | getline car il vous permet d'attraper la valeur dans une variable:

$ awk 'BEGIN {"date" | getline mydate; close("date"); print "returns", mydate}' 
returns Thu Jul 28 10:16:55 CEST 2016 

Plus généralement, vous pouvez définir la commande dans une variable:

awk 'BEGIN { 
     cmd = "date -j -f %s" 
     cmd | getline mydate 
     close(cmd) 
    }' 

Notez qu'il est important de utilisez close() pour éviter d'obtenir une erreur "fait trop de fichiers ouverts" si vous avez plusieurs résultats (merci mateuscb pour avoir signalé cela dans les commentaires).


En utilisant system(), la sortie de commande est imprimée automatiquement et la valeur que vous pouvez prendre est son code de retour:

$ awk 'BEGIN {d=system("date"); print "returns", d}' 
Thu Jul 28 10:16:12 CEST 2016 
returns 0 
$ awk 'BEGIN {d=system("ls -l asdfasdfasd"); print "returns", d}' 
ls: cannot access asdfasdfasd: No such file or directory 
returns 2 
+2

+1 pour ajouter 'close()', si vous ne l'ajoutez pas, et que vous obtenez plusieurs résultats, vous risquez d'avoir "trop ​​de fichiers ouverts". Si vous avez une commande plus longue, vous pouvez faire 'cmd =" ​​date -j -f% s "; cmd | getline mydate; close (cmd) ' – mateuscb

+1

@mateuscb merci beaucoup pour vos commentaires. J'ai mis à jour la question pour inclure vos commentaires utiles. – fedorqui

+1

Merci pour le rappel de la commande close(). Ça aide beaucoup. Sans mettre près(), je reçois parfois un mauvais résultat de date pour plusieurs résultats. Avec mettre près(). mes résultats de plusieurs dates sont tous correctement affichés. – csu007

Questions connexes