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
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óbbanprintf "$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
-vhaszná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.
REPLYaz alapértelmezettnameargumentum areadbeépített shell parancshoz. - Ne feledje, hogy ehhez a héj alapértelmezett változóval használja az adatok beillesztését a
readfájlba, amitbashmegtesz , de ez nem szabványos. Ezenkívül areadparancs 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
awk 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
sh 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és3az 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*). Aechoezen 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
echo "${var//,/$'\n'}")