Usando la sustitución de variables bash en lugar de cut / awk

¿Puedo utilizar la sustitución de variables bash para extraer una parte de una variable basada en un delimitador? Estoy intentando obtener el nombre de directorio inmediato de un nombre de archivo (en este caso, foo).

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

Sé que podría hacer algo como

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

o

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

pero » s se está volviendo lento para bifurcar awk / cut para varios nombres de archivo.

Hice un pequeño perfil de las diversas soluciones , usando mis archivos reales:

echo | cortar:

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

echo | awk:

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

Sustitución de variable de @steeldriver / expansión de parámetro de shell:

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

@jai_s «s IFS-wrangling:

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

Ambas sugerencias fueron una gran mejora con respecto a mis ideas existentes, pero la sustitución de variables es más rápida porque no requieren bifurcar cualquier proceso nuevo.

Comentarios

  • gnu.org/software/bash/manual / html_node / …
  • Envíe todos los nombres de archivo a una invocación de awk y será significativamente más rápido que cualquier solución en bash puro
  • ¿No puedes usar una matriz, hacerlas todas a la vez y luego ponerlas en una nueva matriz?

Responder

Puede eliminar la subcadena inicial más corta que coincida con */

tmp="${filename#*/}" 

y luego eliminar la más larga subcadena final que coincide con /*

Respuesta

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

con comodín con el que parece funcionar comillas dobles o simples –

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

sí, tendrá que desarmar el IFS de nuevo a los valores predeterminados

 unset IFS 

Comentarios

  • Ooh, me gusta.
  • Este suele ser mi método preferido también, pero ten en cuenta que Bash solo admite $1 a $9 con esta sintaxis. Para los argumentos del décimo y posteriores, se debe utilizar la forma ${10}.
  • No ' t funciona cuando $f contiene comodines. Y necesita restaurar IFS después (o hacer esto en una sustitución de comando, para obtener el valor de un campo, y eso elimina las nuevas líneas finales).
  • El ejemplo funciona de forma aislada (dentro de Git bash en Windows), pero cuando canalizo desde el comando de búsqueda, obtengo este error: echo: write error: Bad address.
  • De acuerdo, parece Tengo que unset IFS cada vez.

Responder

Feed la lista a awk para acelerarla:

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

Demostración:

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 

Respuesta

¿Por qué no utiliza el comando» dirname «, en lugar de todo esto awk / sed / cortar cosas?

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

Rendimientos:

./foo/bar 

Comentarios

  • En este caso, estaba buscando el directorio inmediato, no la ruta completa del directorio.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *