Příkaz Awk uvnitř smyčky for

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

  • Každý znak mezi dvojicí jednoduchých uvozovek je považován za doslovný znak.
  • Jaký je váš skutečný případ použití? smyčky přes awk se zde zdají zbytečné (pro exaple v bash můžete použít substituci parametrů echo "${var//,/$'\n'}")
  • Vlastně proměnná bude obsahovat adresy URL zenity. Chci tyto adresy URL používat samostatně, takže musím každou z nich získat samostatně.
  • Relevantní, ale v tomto případě ne dobré řešení: Jak přiřadit hodnotu za běhu v příkazu AWK

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ěji printf "$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 pro read 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říkaz read 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ěď

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

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 a 3 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 

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *