Awk-komento for -silmukan sisällä

Yritän ilman menestystä käyttää awk -komentoa for -silmukka.

Minulla on muuttuja, joka sisältää sarjan merkkijonoja, jotka haluan leikata awk saada tietoja.

Tiedän miten se tehdään, mutta mitä todella haluan on leikata tiedot peräkkäin.

Joten sain tämän muuttujan:

var="data1,data2,data3" 

Ja tässä missä olen tällä hetkellä:

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

Yritän korvata $1 silmukan kautta $i, mutta ei menestystä.

Kommentit

  • Jokaista merkkiä parin lainausmerkin välissä pidetään kirjaimena.
  • Mikä on todellinen käyttötapasi? silmukan luominen awk: n kohdalla näyttää tässä olevan tarpeetonta (esim. bashissa voit käyttää parametrikorvausta echo "${var//,/$'\n'}")
  • Itse asiassa muuttuja sisältää URL-osoitteita zenitymuodosta. Haluan käyttää näitä URL-osoitteita erikseen, joten minun on hankittava kukin niistä itsenäisesti.
  • Asiaankuuluva, mutta ei hyvä ratkaisu tässä tapauksessa: Kuinka Määritä arvo suorituksen aikana AWK-komennossa

Vastaa

Voit suorittaa uudestaan yrittää tehdä lisäämällä shell-muuttujan awk-komentosarjassa olevilla kaksoislainausmerkeillä. Haluat silti pitää siinä yhden kirjaimellisen $, jonka voit tehdä välttämällä sen kääntämällä vinoviivaa :

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

Tämä laajentaa $i muotoon 1, 2 ja 3 kussakin iteraatiossa, joten awk näyttää $1, $2 ja $3 mikä saa sen laajentamaan kutakin kenttää.

Toinen mahdollisuus on injektoida shell-muuttuja awk-muuttuja -v -lipun avulla :

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

Tämä määrittää awk-muuttujan i saman nimisen shell-muuttujan sisältöön. Awk: n muuttujat eivät käytä $ -kenttää, jota käytetään kentissä, joten $i riittää viittaamaan i . kenttä, jos i on muuttuja awk-tiedostossa.

awk-muuttujan määrittäminen -v: n kanssa on yleensä turvallisempaa. lähestymistapa, varsinkin kun se voi sisältää mielivaltaisia merkkijonoja, siinä tapauksessa on pienempi riski, että sisältö suoritetaan awk-koodina aikomuksiasi vasten. Mutta koska sinun tapauksessasi muuttujalla on yksi kokonaisluku, siitä ei ole vähemmän huolta.

Vielä yksi vaihtoehto on käyttää for -silmukkaa itsessään awk . Katso awk-ohjeista (tai hae tältä sivustolta) lisätietoja siitä.

Kommentit

  • … tai aseta syötetietue erotin asianmukaisesti awk -v RS='[,\n]' 1 <<< "$var" (tai ehkä kannettavammin printf "$var" | awk -v RS=, 1)
  • @steeldriver Tuo awk-skripti tulostaa kaikki kolme kenttää osoitteessa Mikä on kunnossa, kun OP tekee juuri sitä … päädyin keskittämään vastauksen yhden kentän purkamiseen oletukseen, että he olivat kiinnostuneita suorittamaan muita komentoja shell-silmukassa (mikä saattaa ovat olleet motivaationa sellaisen käyttämiselle ensiksi …)
  • Ymmärretty – että ’ miksi kommentoin toimenpideohjelmaa selvittääkseen, mitä he todella haluavat tehdä;)
  • ensimmäinen on injektio (ja turvallisuusongelma), toinen o ne (käyttämällä -v) ei ole injektio.
  • Kiitos, vastauksesi ratkaisi ongelmani! Ensimmäisen kerran lähetän kysymyksen tähän vuosien lukemisen jälkeen. Ei pettynyt. Tällainen loistava yhteisö!

Vastaa

Käyttämällä awk näyttää liiallinen tässä tilanteessa, entä tr ja while-loop:

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

Lähtö:

data1 data2 data3 

Kommentit

  • Hienoa. REPLY oletusarvoinen name-argumentti read sisäänrakennetulle komentokomennolle.
  • Huomaa, että tämä edellyttää, että kuori käyttää oletusmuuttujaa tietojen sijoittamiseen kohteesta read, mikä bash sattuu tekemään , mutta tämä ei ole vakio. Myös read -komentosi voi muokata tietoja, jos se sisältää taaksepäin osoittavia viivoja, ja voi poistaa reunan reunan tyhjät tilat arvoista. Se lukisi myös arvot upotetuilla uusilla viivoilla useina arvoina. Tarvitset lisäksi "$REPLY" estääksesi kuoren jakamasta arvoa ja suorittamasta tiedostonimen laajennusta siihen.

vastaus

voi hyväksyä sekä j (muuttujana) että $j (kenttäindeksinä):

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

$i esimerkissä” sekava ”awk mitä käyttää (kuori tai oma muuttuja – etusijalla), koska molempiin viitataan $ -etuliitteellä.

muistiinpano

-sarja, joka on vakio ”kannettaville” komentosarjoille, ei tue:

(( i=1; i<=3; i++; )) ja <<< $var rakentaa

Voit myös harkita seq -komennon käyttämistä for -silmukka tarkempaan hallintaan numerosarjojen luomisessa, jos käytettävissä.

Kommentit

  • Silmukka toimisi vain, jos satunnaisesti kutsutaan kolme tiedostoa , 2 ja 3 nykyisessä hakemistossa. Käytät myös muuttujan laajennusta, jota ei ole mainittu kuoressa ja jolla voi olla ei-toivottuja seurauksia, jos tiedot sisältävät tiedostonimikuvioita (kuten *). echo voi lisäksi muokata tietoja, jos se sisältää taaksepäin viivoja.

Vastaa

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

Tässä muuttujakorvikkeita käytetään saamaan kukin peräkkäinen pilkulla erotettu tietokenttä muuttujan var arvosta. Silmukan ensimmäinen tehtävä data -kohtaan poistaa kaiken $var -kohdasta ensimmäisen pilkun jälkeen. Muuttujaa var muutetaan sitten siten, että ensimmäinen bitti ensimmäiseen pilkkuun asti poistetaan.

Tämä jatkuu, kunnes "$var" = "$data" mikä tarkoittaa, että merkkijonolle ei voida tehdä mitään muuta.

Tämä tapa tehdä se antaisi meille mahdollisuuden käsitellä pilkuilla erotettuja tietojonoja, jotka sisältävät upotettuja uusia rivejä:

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

Jos yllä olevilla arvoilla on var, yllä oleva komentosarja tuottaisi

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

Ei välitä upotetuista uusista viivoista; hyvin harvoin sinun on siirryttävä awk -kehotusten yli.

Huomaa, että awk lukee merkkijonon mielellään pilkulla erotettujen kenttien joukoksi ja pystyy silmukkaamaan näitä:

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

Kanssa var="data1,data2,data3", tämä tulostaa

data1 data2 data3 

Toinen kuoriratkaisu, joka käyttää IFS -muuttuja jakamaan $var -arvo bitteihin ja samalla käyttämään set -f -toimintoa tiedostonimen laajennuksen poistamiseksi käytöstä:

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

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *