Použití substituce proměnné bash namísto cut / awk

Mohu použít substituci proměnné bash k extrahování části proměnné na základě delimetru? Snažím se získat okamžitý název adresáře názvu souboru (v tomto případě foo).

$ filename=./foo/bar/baz.xml 

Vím, že bych mohl udělat něco jako

echo $filename | cut -d "/" -f 2 

nebo

echo $filename | awk -F "/" "{print $2}" 

ale ono “ pomalu se rozvíjí awk / cut pro více názvů souborů.

Udělal jsem trochu profilování různých řešení , pomocí mých skutečných souborů:

echo | cut:

real 2m56.805s user 0m37.009s sys 1m26.067s 

echo | awk:

real 2m56.282s user 0m38.157s sys 1m31.016s 

@steeldriver je variabilní substituce / rozšíření parametrů shellu:

real 0m0.660s user 0m0.421s sys 0m0.235s 

@jai_s „s IFS-wrangling:

real 1m26.243s user 0m13.751s sys 0m28.969s 

Oba návrhy byly velkým zlepšením oproti mým stávajícím nápadům, ale variabilní substituce je nejrychlejší, protože to nejde požadovat rozdvojení všech nových procesů.

Komentáře

  • gnu.org/software/bash/manual / html_node / …
  • Odeslat všechny názvy souborů na jedno vyvolání awk a bude to podstatně rychlejší než jakékoli řešení v čistém bash
  • Nemůžete použít pole, proveďte všechny najednou a poté ho vložte do nového pole?

Odpovědět

Můžete odstranit nejkratší podřetězec, který odpovídá */

tmp="${filename#*/}" 

a poté odstranit nejdelší koncový podřetězec, který odpovídá /*

Odpověď

 echo $f a/b/c $ (IFS="/";set $f; echo $1) a $ (IFS="/";set $f; echo $2) b $ (IFS="/";set $f; echo $3) c 

s divokou kartou se zdá, že funguje s dvojité nebo jednoduché uvozovky –

 f="a?b?c" $(IFS="?"; set $f; echo $1) a echo $f a*b*c (IFS="*"; set $f; echo $1) a 

ano, budete muset IFS znovu nastavit na výchozí

 unset IFS 

Komentáře

  • Ó, to se mi líbí.
  • Toto je také obvykle moje preferovaná metoda, ale mějte na paměti, že Bash pomocí této syntaxe podporuje pouze $1$9. U 10. a novějších argumentů musí být použit ${10} formulář.
  • ' nefunguje, když $f obsahuje zástupné znaky. A budete muset IFS později obnovit (nebo to provést v substituci příkazu, abyste získali hodnotu pole a tím se odstranily koncové řádky).
  • Příklad funguje izolovaně (uvnitř Git bash v systému Windows), ale když přepojím z příkazu find, zobrazí se tato chyba: echo: write error: Bad address.
  • Dobře, vypadá to Musím unset IFS pokaždé.

Odpovědět

Feed seznam awk pro urychlení:

awk -F "/" "{print $2}" < <(find /usr) awk -F "/" "{print $2}" < inputfile 

Demonstrace:

time awk -F "/" "{print $2; SUM++} END {print "number of directories found: " SUM}" < <(find /usr -type d) usr usr . . number of directories found: 16748 real 0m8.910s user 0m0.050s sys 0m0.050s 

Odpovědět

Proč nepoužíváte příkaz“ dirname „, místo toho všeho awk / sed / řezané věci?

filename=./foo/bar/baz.xml dirname $filename 

Výnosy:

./foo/bar 

Komentáře

  • V tomto případě jsem hledal okamžitý adresář, nikoli úplnou cestu k adresáři.

Napsat komentář

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