Awk parancs egy for cikluson belül

Igyekszem sikertelenül használni a awk parancsot egy for ciklus.

Van egy változóm, amely egy sor karakterláncot tartalmaz, amelyeket le akarok vágni awk hogy megszerezzem az adatokat.

Tudom, hogyan kell ezt megtenni, de amit igazán szeretnék, az az, hogy egymás után vágom az adatokat.

Tehát megkaptam ezt a változót:

var="data1,data2,data3" 

És itt vagyok, ahol éppen vagyok:

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

Megpróbálom lecserélni a $1 a hurok által $i, de sikertelenül.

Megjegyzések

  • Az egyes idézőjelek közötti karaktereket szó szerinti karakterként kezeljük.
  • Mi a valódi felhasználási esete? Az awk-hurkolás itt feleslegesnek tűnik (a bash-ban az exaple-hez használhat egy paraméter-helyettesítést echo "${var//,/$'\n'}")
  • Valójában a változó egy zenity formából származó URL-eket tartalmaz. Ezeket az URL-eket külön szeretném használni, így mindegyiket külön-külön kell megszereznem.
  • Ebben az esetben releváns, de nem jó megoldás: Hogyan hozzárendelje az értéket futás közben az AWK parancsban

Válasz

Meg tudja valósítani, amit újra az awk szkriptben dupla idézőjelek segítségével megpróbálja beinjektálni a shell változót. Még mindig meg akar tartani benne egy literal $ szót, amit megtehet, ha visszavágással elkerüli :

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

Ez kibővíti a $i elemet 1, 2 és 3 az egyes iterációkban, ezért az awk $1, $2 és $3 ami kiterjeszti az egyes mezőket.

Egy másik lehetőség az, hogy a shell változót mint awk változó a -v zászló használatával :

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

Ez hozzárendeli az awk i változót az azonos nevű shell változó tartalmához. Az awk változói nem használnak egy mezőkhöz használt $ -t, ezért $i elegendő az i hivatkozásra a harmadik mező, ha az i az awk változója.

Egy awk változó hozzárendelése a -v ponttal általában biztonságosabb megközelítés, különösen akkor, ha tetszőleges karaktersorozatot tartalmazhat, ebben az esetben kisebb a kockázata annak, hogy a tartalmat awk kódként futtassuk a szándékai ellenére. De mivel a te esetedben a változó egyetlen egész számot tartalmaz, ez kevésbé aggasztó.

Egy másik lehetőség egy for ciklus használata az awk-ban . További részletekért lásd az awk dokumentációját (vagy keressen ezen a webhelyen).

Megjegyzések

  • … vagy állítsa be a bemeneti rekordot elválasztó megfelelően awk -v RS='[,\n]' 1 <<< "$var" (vagy esetleg hordozhatóbban printf "$var" | awk -v RS=, 1)
  • @steeldriver Ez az awk szkript mindhárom mezőt kinyomtatja Amely rendben van, mivel az OP éppen ezt csinálja … végül a választ arra összpontosítottam, hogy egyetlen mezőt nyerjek ki abból a feltételezésből, hogy érdekeltek a parancssor többi parancsának végrehajtásában (ami motiválta az egyik használatát …)
  • Megértettem – ezért ‘ miért kommentáltam az OP-t, hogy tisztázzam, mit igazán tenni akarok;)
  • Az első injekció (és biztonsági aggály), a második o a ne (a -v használata) nem injekció.
  • Köszönöm, válaszod megoldotta a problémámat! Először felteszek egy kérdést ide, miután évek óta olvasom a bejegyzéseket. Nem csalódott. Ilyen nagyszerű közösség!

Válasz

Úgy tűnik, hogy a awk túlzott ebben a helyzetben, mit szólna egy tr és egy while-ciklushoz:

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

Kimenet:

data1 data2 data3 

Megjegyzések

  • Remek. REPLY az alapértelmezett name argumentum a read beépített shell parancshoz.
  • Ne feledje, hogy ehhez a héj alapértelmezett változóval használja az adatok beillesztését a read fájlba, amit bash megtesz , de ez nem szabványos. Ezenkívül a read parancs módosíthatja az adatokat, ha visszavágásokat tartalmaz, és eltávolíthatja a határoló szóközt az értékektől. Ez a beágyazott új vonalakkal rendelkező értékeket is több értékként olvassa el. Ezenkívül szükség van a "$REPLY" -re, hogy megakadályozza a héj felosztását és a fájlnév-bővítés végrehajtását rajta.

Válasz

elfogadható j (változóként) és $j (mező indexként):

re class = “lang-sh prettyprint- a “zavart” awk melyiket kell használni (shell vagy saját változó – elsőbbséget élvezve), mivel mindkettőre $ előtaggal utalunk.

megjegyzés

shell, amely a “hordozható” szkripteknél szabványos, nem támogatja:

(( i=1; i<=3; i++; )) és <<< $var konstrukciók

Fontolja meg az seq parancs használatát a for hurok a finomabb vezérléshez a számsorozat létrehozásában, ha rendelkezésre áll.

Megjegyzések

  • A hurok csak akkor működne, ha véletlenül három fájlt hívna meg , 2 és 3 az aktuális könyvtárban. Ezenkívül változó kiterjesztést is használ a héjban, amely nem kívánt következményekkel járhat, ha az adatok fájlnévmintákat tartalmaznak (például *). A echo ezen felül módosíthatja az adatokat, ha visszavágásokat tartalmaznak.

Válasz

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

Itt változó helyettesítéssel minden egyes egymást követő vesszővel elválasztott adatmezőt a var változó értékéből kapunk. A ciklusban a data első hozzárendelése mindent eltávolít az $var ből az első vessző után. A var változó ezután módosul, így az első bit az első vesszőig törlődik.

Ez addig folytatódik, amíg "$var" = "$data" ami azt jelenti, hogy nem lehet többet tenni a karaktersorozattal.

Ez a módszer lehetővé tenné vesszővel elválasztott adatsorok kezelését, amelyek beágyazott új sorokat tartalmaznak:

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

Ha a fenti értékek szerepelnek a var fájlban, a fenti szkript kiadná

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

Nem törődnek a beágyazott új sorokkal; nagyon ritkán hurkolnia kell a awk invokációit.

Ne feledje, hogy awk tökéletesen örül, ha vesszővel elválasztott mezőként olvassa el a karakterláncot, és képes ezekre hurokolni:

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

var="data1,data2,data3", ez kinyomtatja

data1 data2 data3 

Egy másik shell megoldás, amely a változó az $var érték bitekre bontásához, a set -f használatával a fájlnév kibővítésének letiltásához is:

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

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük