Posso utilizzare la sostituzione della variabile bash per estrarre una parte di una variabile basata su un delimetro? Sto cercando di ottenere il nome della directory immediata di un nome di file (in questo caso, foo
).
$ filename=./foo/bar/baz.xml
So che potrei fare qualcosa come
echo $filename | cut -d "/" -f 2
o
echo $filename | awk -F "/" "{print $2}"
ma ” sta diventando lento nel fork di awk
/ cut
per più nomi di file.
Ho fatto un po di profilazione delle varie soluzioni , usando i miei file reali:
echo | cut:
real 2m56.805s user 0m37.009s sys 1m26.067s
echo | awk:
real 2m56.282s user 0m38.157s sys 1m31.016s
@steeldriver “sostituzione variabile / espansione parametro shell:
real 0m0.660s user 0m0.421s sys 0m0.235s
@jai_s “s IFS-wrangling:
real 1m26.243s user 0m13.751s sys 0m28.969s
Entrambi i suggerimenti sono stati un enorme miglioramento rispetto alle mie idee esistenti, ma la sostituzione delle variabili è più veloce perché non” t richiedono il fork di nuovi processi.
Commenti
- gnu.org/software/bash/manual / html_node / …
- Invia tutti i nomi di file a una chiamata di awk e sarà significativamente più veloce di qualsiasi soluzione in puro bash
- Non puoi usare un array, eseguirli tutti in una volta e poi metterlo in un nuovo array?
Risposta
Puoi rimuovere la sottostringa iniziale più corta che corrisponde a */
tmp="${filename#*/}"
e quindi rimuovere la più lunga sottostringa finale che corrisponde a /*
Risposta
echo $f a/b/c $ (IFS="/";set $f; echo $1) a $ (IFS="/";set $f; echo $2) b $ (IFS="/";set $f; echo $3) c
con carattere jolly sembra funzionare con virgolette doppie o singole –
f="a?b?c" $(IFS="?"; set $f; echo $1) a echo $f a*b*c (IFS="*"; set $f; echo $1) a
sì, dovrai annullare limpostazione predefinita dellIFS
unset IFS
Commenti
- Ooh, mi piace.
- Di solito è anche il mio metodo preferito, ma tieni presente che Bash supporta solo da
$1
a$9
utilizzando questa sintassi. Per il decimo argomento e quelli successivi, è necessario utilizzare il modulo${10}
. - ' t funziona quando
$f
contiene caratteri jolly. E devi ripristinareIFS
in seguito (o farlo in una sostituzione di comando, per ottenere il valore di un campo e questo rimuove le nuove righe finali). - Lesempio funziona in isolamento (allinterno di Git bash su Windows), ma quando eseguo il pipe dal comando find ottengo questo errore:
echo: write error: Bad address
. - Va bene, sembra Devo
unset IFS
ogni volta.
Risposta
Feed lelenco da awk
per velocizzarlo:
awk -F "/" "{print $2}" < <(find /usr) awk -F "/" "{print $2}" < inputfile
Dimostrazione:
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
Risposta
Perché non usi il comando” dirname “, invece di tutto questo awk / sed / tagliare cose?
filename=./foo/bar/baz.xml dirname $filename
Rendimenti:
./foo/bar
Commenti
- In questo caso stavo cercando la directory immediata, non il percorso completo della directory.