Använda bash-variabelsubstitution istället för cut / awk

Kan jag använda bash-variabelersättning för att extrahera en bit av en variabel baserat på en avgränsare? Jag försöker få det omedelbara katalognamnet på ett filnamn (i det här fallet foo).

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

Jag vet att jag kunde göra något som

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

eller

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

men det ” s blir långsam att gaffla awk / cut för flera filnamn.

Jag gjorde en liten profilering av de olika lösningarna , med mina riktiga filer:

echo | klipp:

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

eko | awk:

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

@steeldrivers variabla substitution / skalparameterutvidgning:

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

@jai_s ”IFS-wrangling:

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

Båda förslagen var en enorm förbättring jämfört med mina befintliga idéer, men den variabla ersättningen är snabbast eftersom den inte kräver att nya processer släpps.

Kommentarer

  • gnu.org/software/bash/manual / html_node / …
  • Skicka alla filnamn till en anrop av awk och det blir betydligt snabbare än någon lösning i ren bash
  • Kan du inte använda en matris, gör alla på en gång och placerar den i en ny matris?

Svar

Du kan ta bort den kortaste ledande strängen som matchar */

tmp="${filename#*/}" 

och sedan ta bort den längsta efterföljande underlag som matchar /*

Svar

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

med jokertecken som det verkar fungera med dubbla eller enkla citat –

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

ja, du måste avaktivera IFS tillbaka till standard

 unset IFS 

Kommentarer

  • Ooh, jag gillar det.
  • Detta är vanligtvis min föredragna metod också, men kom ihåg att Bash stöder endast $1 till $9 med denna syntax. För 10: e och senare argument måste ${10} -formuläret användas.
  • Fungerar inte ' t när $f innehåller jokertecken. Och du måste återställa IFS efteråt (eller gör det i ett kommandosubstitution för att få värdet av ett fält och som avlägsnar efterföljande nya rader).
  • Exemplet fungerar isolerat (inuti Git bash på Windows), men när jag rör från find-kommandot får jag det här felet: echo: write error: Bad address.
  • Okej, ser ut som Jag måste unset IFS varje gång.

Svar

Feed listan till awk för att påskynda den:

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

Demonstration:

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 

Svar

Varför använder du inte kommandot” dirname ”istället för allt detta awk / sed / klippa saker?

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

Avkastning:

./foo/bar 

Kommentarer

  • I det här fallet letade jag efter den omedelbara katalogen, inte hela katalogvägen.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *