Snažím se bez úspěchu použít příkaz awk
uvnitř for
smyčka.
Mám proměnnou, která obsahuje řadu řetězců, které chci vyjmout pomocí awk
získat data.
Vím, jak to udělat, ale to, co opravdu chci, je data postupně vyjmout.
Takže mám tuto proměnnou:
var="data1,data2,data3"
A tady, kde jsem právě teď:
for ((i=1; i<=3; i++)) do echo $(awk -F, "{print $1}" <<< $var) done
Snažím se nahradit $1
smyčkou $i
, ale bez úspěchu.
Komentáře
odpověď
Můžete dosáhnout toho, čeho jste zkuste to pomocí dvojitých uvozovek ve skriptu awk, abyste do něj vložili proměnnou shellu. Stále si v ní chcete ponechat jeden doslovný $
, což můžete udělat únikem zpětného lomítka :
echo $(awk -F, "{print \$$i}" <<<$var)
Tím se rozšíří $i
na 1
, 2
a 3
v každé z iterací, proto awk uvidí $1
, $2
a $3
které způsobí, že se rozšíří každé z polí.
Další možností je vložit proměnnou prostředí jako Proměnná awk používající příznak -v
:
echo $(awk -F, -v i="$i" "{print $i}" <<<$var)
To přiřadí proměnné awk i obsahu proměnné prostředí se stejným názvem. Proměnné v awk nepoužívají $
, který se používá pro pole, takže $i
stačí k odkazu na i -té pole, pokud i je proměnná v awk.
Přiřazení proměnné awk pomocí -v
je obecně bezpečnější přístup, zvláště když může obsahovat libovolné sekvence znaků, v takovém případě existuje menší riziko, že obsah bude proveden jako awk kód proti vašim záměrům. Ale protože ve vašem případě proměnná obsahuje jedno celé číslo, není to tak důležité.
Další možností je použít smyčku for
v samotném awk . Další informace o tom, jak to udělat, najdete v dokumentaci awk (nebo prohledejte tento web).
Komentáře
- … nebo nastavte vstupní záznam vhodně oddělovač
awk -v RS='[,\n]' 1 <<< "$var"
(nebo snad přenosnějiprintf "$var" | awk -v RS=, 1
) - @steeldriver Tento skript awk vytiskne všechna tři pole na jednou. Což je v pořádku, vzhledem k tomu, že OP dělá právě to … Nakonec jsem odpověď zaměřil na extrahování jednoho pole za předpokladu, že měli zájem o provedení dalších příkazů ve smyčce shellu (což by byly motivací k použití jednoho na prvním místě …)
- Rozumím – proto ‚ jsem proto komentoval OP, abych objasnil, co opravdu chcete udělat;)
- První první je injekce (a bezpečnostní problém), druhý o ne (using
-v
) není injekce. - Díky, vaše odpověď vyřešila můj problém! Poprvé sem pošlu otázku po letech čtení příspěvků. Není zklamaný. Skvělá komunita!
Odpověď
Zdá se, že používání awk
za těchto okolností nadměrné, co třeba tr
a while-loop:
tr , "\n" <<<"$var" | while read; do echo $REPLY done
Výstup:
data1 data2 data3
Komentáře
- Skvělé.
REPLY
je výchozíname
argument proread
příkaz vestavěného prostředí. - Všimněte si, že to vyžaduje, aby shell použil výchozí proměnnou k vložení dat z
read
, cožbash
náhodou dělá , ale to není standardní. Váš příkazread
může také upravit data, pokud obsahují zpětná lomítka, a může z hodnot odstranit mezeru. Také by četlo hodnoty s vloženými novými řádky jako více hodnot. Dále musíte"$REPLY"
zastavit shell v rozdělení hodnoty a v provádění rozšiřování názvu souboru.
Odpověď
awk může přijmout j
(jako proměnná) a $j
(jako index pole):
for i in 1 2 3; do echo "$var" | awk -v j=$i -F , "{print $j}"; done
$i
v příkladu“ confused „awk
který z nich použít (shell nebo jeho vlastní proměnná – má přednost), protože na oba se odkazuje s předponou $
.
poznámka
sh prostředí, které je standardem pro „přenosné“ skriptování, nepodporuje:
(( i=1; i<=3; i++; ))
a <<< $var
konstrukty
Také můžete zvážit použití příkazu seq
v for
pro jemnější ovládání při generování číselných sekvencí, pokud je k dispozici.
Komentáře
- Vaše smyčka by fungovala, pouze pokud byste náhodou měli tři soubory s názvem ,
2
a3
v aktuálním adresáři. Také používáte proměnnou expanzi bez kotace v prostředí, což může mít nežádoucí důsledky, pokud data obsahují vzory souborů (například*
).echo
může dále upravovat data, pokud obsahují zpětná lomítka.
Odpovědět
#!/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
Zde používáme substituce proměnných k získání každého následného datového pole odděleného čárkami z hodnoty proměnné var
. První přiřazení data
ve smyčce odstraní vše z $var
za první čárkou. Proměnná var
se poté upraví tak, aby se odstranil první bit až po první čárku.
Takto to pokračuje, dokud "$var" = "$data"
, což znamená, že s řetězcem nelze nic dělat.
Tento způsob by nám umožnil zpracovat datové řetězce oddělené čárkami, které obsahují vložené nové řádky:
var="line1 line2,data2,last bit goes here"
S výše uvedenými hodnotami v var
by se výše uvedený skript zobrazil
data = "line1 line2" data = "data2" data = "last bit goes here"
Nezajímá mě vložené nové řádky; Velmi zřídka musíte procházet vyvoláváními awk
.
Upozorňujeme, že awk
je naprosto šťastný, že čte váš řetězec jako sadu polí oddělených čárkami a že je schopen smyčku přes tato:
printf "%s\n" "$var" | awk -F "," "{ for (i=1; i<=NF; i++) print $i }"
With var="data1,data2,data3"
, vytiskne se
data1 data2 data3
Další prostředí, které využívá IFS
proměnná k rozdělení $var
hodnoty na bity a zároveň použití set -f
k deaktivaci rozšíření názvu souboru:
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'}"
)