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 moetIFS
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.