Commande Awk dans une boucle for

Jessaye, sans succès, dutiliser une commande awk dans un for boucle.

Jai une variable qui contient une série de chaînes que je veux couper avec awk pour obtenir les données.

Je sais comment faire mais ce que je veux vraiment, cest couper les données successivement.

Jai donc cette variable:

var="data1,data2,data3" 

Et ici où je suis en ce moment:

for ((i=1; i<=3; i++)) do echo $(awk -F, "{print $1}" <<< $var) done 

Jessaye de remplacer le $1 par la boucle $i mais sans succès.

Commentaires

  • Chaque caractère entre une paire de guillemets simples est traité comme un caractère littéral.
  • Quel est votre véritable cas dutilisation? boucler sur awk semble inutile ici (par exemple dans bash, vous pouvez utiliser une substitution de paramètre echo "${var//,/$'\n'}")
  • En fait, la variable contiendra des URL dune forme zénité. Je veux utiliser ces URL séparément, donc je dois obtenir chacune delles indépendamment.
  • Pertinent, mais pas une bonne solution dans ce cas: Comment faire attribuer une valeur au moment de lexécution dans la commande AWK

Réponse

Vous pouvez accomplir ce que vous « êtes essayez de faire en utilisant des guillemets doubles dans le script awk pour y injecter la variable shell. Vous voulez toujours conserver un littéral $, ce que vous pouvez faire en léchappant avec une barre oblique inverse :

echo $(awk -F, "{print \$$i}" <<<$var) 

Cela étendra le $i à 1, 2 et 3 dans chacune des itérations, par conséquent awk verra $1, $2 et $3 ce qui le fera étendre chacun des champs.

Une autre possibilité est dinjecter la variable shell comme un variable awk utilisant lindicateur -v :

echo $(awk -F, -v i="$i" "{print $i}" <<<$var) 

Cela assigne la variable awk i au contenu de la variable shell du même nom. Les variables dans awk nutilisent pas de $, qui est utilisé pour les champs, donc $i suffit pour faire référence au i -th champ si i est une variable dans awk.

Assigner une variable awk avec -v est généralement plus sûr approche, en particulier quand il peut contenir des séquences arbitraires de caractères, dans ce cas, il y a moins de risque que le contenu soit exécuté comme du code awk contre vos intentions. Mais comme dans votre cas, la variable contient un seul entier, cest moins un problème.

Encore une autre option consiste à utiliser une boucle for dans awk lui-même . Consultez la documentation awk (ou recherchez sur ce site) pour plus de détails sur la façon de procéder.

Commentaires

  • … ou définissez lenregistrement dentrée séparateur de manière appropriée awk -v RS='[,\n]' 1 <<< "$var" (ou peut-être plus facilement printf "$var" | awk -v RS=, 1)
  • @steeldriver Ce script awk imprimera les trois champs ce qui est correct étant donné que lOP fait exactement cela … Jai fini par concentrer la réponse sur lextraction dun seul champ en supposant quils étaient intéressés à exécuter dautres commandes dans la boucle du shell (ce qui ont été la motivation pour en utiliser un en premier lieu …)
  • Compris – que ‘ s pourquoi jai commenté le PO pour clarifier ce quils vraiment vouloir faire;)
  • Le premier est une injection (et un problème de sécurité), le deuxième o ne (utiliser -v) nest pas une injection.
  • Merci, votre réponse a résolu mon problème! La première fois que je poste une question ici après des années de lecture de messages. Pas déçu. Une si grande communauté!

Réponse

Lutilisation de awk semble excessif dans cette circonstance, que diriez-vous dun tr et dune boucle while:

tr , "\n" <<<"$var" | while read; do echo $REPLY done 

Résultat:

data1 data2 data3 

Commentaires

  • Excellent. REPLY étant largument par défaut name pour read commande shell intégrée.
  • Notez que cela nécessite que le shell utilise une variable par défaut pour placer les données de read, ce que bash fait , mais ce nest pas standard. De plus, votre commande read peut modifier les données si elle contient des barres obliques inverses et peut supprimer les espaces flanquants des valeurs. Il lit également les valeurs avec des retours à la ligne incorporés en tant que valeurs multiples. Vous avez également besoin de "$REPLY" pour empêcher le shell de diviser la valeur et deffectuer une expansion de nom de fichier dessus.

Réponse

peut accepter à la fois j (comme variable) et $j (comme index de champ):

 for i in 1 2 3; do echo "$var" | awk -v j=$i -F , "{print $j}"; done  

$i dans lexemple » confused « awk lequel utiliser (shell ou sa propre variable – ayant priorité) car les deux sont désignés par le préfixe $.

note

shell qui est standard pour les scripts « portables » ne prend pas en charge:

(( i=1; i<=3; i++; )) et <<< $var constructions

Vous pouvez également envisager dutiliser la commande seq dans for pour un contrôle plus fin de la génération de séquences de nombres, si disponible.

Commentaires

  • Votre boucle ne fonctionnerait que si vous aviez trois fichiers appelés , 2 et 3 dans le répertoire courant. De plus, vous utilisez le développement de variables sans guillemets dans le shell, ce qui peut avoir des conséquences indésirables si les données contiennent des modèles de nom de fichier (comme *). Le echo peut en outre modifier les données si elles contiennent des barres obliques inverses.

Réponse

#!/bin/sh var="data1,data2,data3" unset data while [ "$var" != "$data" ]; do data=${var%%,*} # delete first comma and the bit after it var=${var#*,} # delete bit up to first comma (and the comma) printf "data = "%s"\n" "$data" done 

Ici, nous utilisons des substitutions de variables pour obtenir chaque champ de données successif délimité par des virgules à partir de la valeur de la variable var. La première affectation à data dans la boucle supprimera tout de $var après la première virgule. La variable var est ensuite modifiée afin que le premier bit jusquà la première virgule soit supprimé.

Cela continue jusquà "$var" = "$data" ce qui signifie que rien de plus ne peut être fait pour la chaîne.

Cette façon de faire nous permettrait de gérer des chaînes de données séparées par des virgules contenant des retours à la ligne intégrés:

var="line1 line2,data2,last bit goes here" 

Avec les valeurs ci-dessus dans var, le script ci-dessus afficherait

data = "line1 line2" data = "data2" data = "last bit goes here" 

Ne se souciant pas des retours à la ligne intégrés; Vous devez très rarement faire une boucle sur les appels de awk.

Notez que awk est parfaitement heureux de lire votre chaîne comme un ensemble de champs délimités par des virgules, et quil est capable de boucler sur ceux-ci:

printf "%s\n" "$var" | awk -F "," "{ for (i=1; i<=NF; i++) print $i }" 

Avec var="data1,data2,data3", cela afficherait

data1 data2 data3 

Une autre solution shell qui utilise le IFS pour diviser la valeur $var en bits tout en utilisant également set -f pour désactiver lexpansion du nom de fichier:

set -f oldIFS=$IFS; IFS="," set -- $var IFS=$oldIFS; unset oldIFS set +f for data do printf "data = "%s"\n" "$data" done 

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *