Substitutie van bash-variabelen gebruiken in plaats van cut / awk

Kan ik substitutie van bash-variabelen gebruiken om een deel van een variabele te extraheren op basis van een delimeter? Ik probeer de directe directorynaam van een bestandsnaam te krijgen (in dit geval foo).

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

Ik weet dat ik zoiets zou kunnen doen

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

of

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

maar het ” s wordt langzaam naar vork awk / cut voor meerdere bestandsnamen.

Ik heb een beetje profilering gemaakt van de verschillende oplossingen , met behulp van mijn echte bestanden:

echo | cut:

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

echo | awk:

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

@steeldriver “s variabele substitutie / shell parameter uitbreiding:

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

@jai_s “s IFS-wrangling:

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

Beide suggesties waren een enorme verbetering ten opzichte van mijn bestaande ideeën, maar de vervanging van variabelen is het snelst omdat het niet vereist forking van nieuwe processen.

Opmerkingen

  • gnu.org/software/bash/manual / html_node / …
  • Stuur alle bestandsnamen naar één aanroep van awk en het zal aanzienlijk sneller zijn dan elke oplossing in pure bash
  • Kunt u geen array gebruiken, ze allemaal tegelijk doen en vervolgens in een nieuwe array plaatsen?

Answer

U kunt de kortste leidende subtekenreeks verwijderen die overeenkomt met */

tmp="${filename#*/}" 

en vervolgens de langste verwijderen achterliggende substring die overeenkomt met /*

Answer

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

met jokerteken waarmee het lijkt te werken dubbele of enkele aanhalingstekens –

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

ja, je “zal de IFS terug moeten zetten naar de standaard

 unset IFS 

Reacties

  • Ooh, dat vind ik leuk.
  • Dit is meestal ook mijn voorkeursmethode, maar houd er rekening mee dat Bash ondersteunt alleen $1 tot en met $9 met behulp van deze syntaxis. Voor 10e en latere argumenten moet het ${10} -formulier worden gebruikt.
  • Werkt niet ' als $f bevat jokertekens. En je moet IFS achteraf herstellen (of doe dit in een opdrachtsubstitutie om de waarde van een veld te krijgen, en dat verwijdert de nieuwe regels achteraan).
  • Het voorbeeld werkt geïsoleerd (binnen Git bash op Windows), maar als ik pipe vanuit het find-commando krijg ik de volgende foutmelding: echo: write error: Bad address.
  • Oké, het ziet eruit als Ik moet elke keer unset IFS.

Beantwoorden

Feed de lijst naar awk om het te versnellen:

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

Demonstratie:

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 

Answer

Waarom” gebruik je niet het “dirname” commando, in plaats van al dit awk / sed / cut stuff?

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

Opbrengsten:

./foo/bar 

Reacties

  • In dit geval zocht ik naar de directe directory, niet het volledige directorypad.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *