Utilizzo della sostituzione della variabile bash invece di cut / awk

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 ripristinare IFS 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.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *