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
-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értelmezettname
argumentum aread
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, amitbash
megtesz , de ez nem szabványos. Ezenkívül aread
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
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
és3
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*
). Aecho
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
echo "${var//,/$'\n'}"
)