¿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 restaurarIFS
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.