Comando Awk allinterno di un ciclo for

Provo, senza successo, a utilizzare un comando awk allinterno di un for loop.

Ho “una variabile che contiene una serie di stringhe che voglio tagliare con awk per ottenere i dati.

So come farlo, ma quello che voglio veramente è tagliare i dati successivamente.

Quindi ho questa variabile:

var="data1,data2,data3" 

Ed ecco dove sono adesso:

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

Provo a sostituire $1 dal ciclo $i ma senza successo.

Commenti

  • Ogni carattere tra una coppia di virgolette singole viene trattato come un carattere letterale.
  • Qual è il tuo vero caso duso? il looping su awk sembra non necessario qui (ad esempio in bash potresti usare una sostituzione di parametro echo "${var//,/$'\n'}")
  • In realtà la variabile conterrà URL da una forma zenity. Voglio usare questi URL separatamente, quindi devo ottenerli ciascuno in modo indipendente.
  • Rilevante, ma non è una buona soluzione in questo caso: Come assegna un valore in fase di esecuzione nel comando AWK

Risposta

Puoi ottenere ciò che vuoi cercando di farlo utilizzando le virgolette doppie nello script awk per iniettare la variabile di shell al suo interno. Vuoi comunque mantenere un $ letterale al suo interno, cosa che puoi fare facendo lescape con la barra rovesciata :

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

Questo espanderà $i a 1, 2 e 3 in ciascuna delle iterazioni, pertanto awk vedrà $1, $2 e $3 che espanderà ciascuno dei campi.

Unaltra possibilità è iniettare la variabile di shell come variabile awk utilizzando il flag -v :

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

che assegna la variabile awk i al contenuto della variabile di shell con lo stesso nome. Le variabili in awk non utilizzano un $, utilizzato per i campi, quindi $i è sufficiente per fare riferimento a i -esimo campo se i è una variabile in awk.

Assegnare una variabile awk con -v è generalmente più sicuro approccio, in particolare quando può contenere sequenze arbitrarie di caratteri, in tal caso cè meno rischio che il contenuto venga eseguito come codice awk contro le tue intenzioni. Ma poiché nel tuo caso la variabile contiene un singolo numero intero, questo è meno preoccupante.

Unaltra opzione è usare un ciclo for in awk stesso . Consulta la documentazione di awk (o cerca nel sito) per maggiori dettagli su come farlo.

Commenti

  • … o imposta il record di input separatore in modo appropriato awk -v RS='[,\n]' 1 <<< "$var" (o forse in modo più portabile printf "$var" | awk -v RS=, 1)
  • @steeldriver Quello script awk stamperà tutti e tre i campi in una volta. Il che è ok dato che lOP sta facendo proprio questo … ho finito per concentrare la risposta sullestrazione di un singolo campo supponendo che fossero interessati a eseguire altri comandi nel ciclo della shell (che potrebbe sono stati la motivazione per usarne uno in primo luogo …)
  • Capito – che ‘ è il motivo per cui ho commentato lOP per chiarire cosa davvero vuole fare;)
  • Il primo è uniniezione (e un problema di sicurezza), il secondo o ne (utilizzando -v) non è uniniezione.
  • Grazie, la tua risposta ha risolto il mio problema! La prima volta che posto una domanda qui dopo anni di lettura di post. Non deluso. Una community così fantastica!

Rispondi

Usare awk sembra eccessivo in questa circostanza, che ne dici di un tr e di un ciclo while:

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

Risultato:

data1 data2 data3 

Commenti

  • Ottimo. REPLY è il name argomento predefinito per read comando della shell incorporato.
  • Tieni presente che ciò richiede che la shell utilizzi una variabile predefinita per inserire i dati da read, cosa che accade a bash , ma questo non è standard. Inoltre, il tuo comando read potrebbe modificare i dati se contengono barre rovesciate e potrebbe rimuovere gli spazi bianchi dai valori. Leggerebbe anche i valori con newline incorporati come valori multipli. È inoltre necessario "$REPLY" per impedire alla shell di suddividere il valore e di eseguire lespansione del nome del file su di esso.

Risposta

può accettare sia j (come variabile) e $j (come indice di campo):

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

$i nellesempio” confused “awk quale usare (shell o la propria variabile – ha la precedenza) poiché entrambi sono indicati con il prefisso $.

nota

che è standard per lo scripting “portabile” non supporta:

(( i=1; i<=3; i++; )) e <<< $var costrutti

Potresti anche prendere in considerazione lutilizzo del comando seq in for loop per un controllo più preciso nella generazione di sequenze numeriche, se disponibile.

Commenti

  • Il tuo loop funzionerebbe solo se ti capita di avere tre file chiamati , 2 e 3 nella directory corrente. Inoltre, utilizzi lespansione delle variabili senza virgolette nella shell che potrebbe avere conseguenze indesiderate se i dati contengono modelli di nomi di file (come *). echo può inoltre modificare i dati se contengono barre rovesciate.

Risposta

#!/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 

In questo caso, utilizziamo sostituzioni di variabili per ottenere ogni successivo campo di dati delimitato da virgole dal valore della variabile var. La prima assegnazione a data nel ciclo rimuoverà tutto da $var dopo la prima virgola. La variabile var viene quindi modificata in modo da eliminare il primo bit fino alla prima virgola.

Questo continua fino a "$var" = "$data" il che significa che non si può fare altro sulla stringa.

Questo modo di farlo ci consentirebbe di gestire stringhe di dati separate da virgole che contengono newline incorporate:

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

Con i valori di cui sopra in var, lo script precedente produrrebbe

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

Non preoccuparsi dei newline incorporati; molto raramente devi eseguire il ciclo di invocazioni di awk.

Tieni presente che awk è perfettamente felice di leggere la tua stringa come un insieme di campi delimitati da virgole e che è in grado di scorrere questi:

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

Con var="data1,data2,data3", verrebbe stampato

data1 data2 data3 

Unaltra soluzione di shell che utilizza IFS per dividere il valore $var in bit utilizzando anche set -f per disabilitare lespansione del nome file:

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

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *