Usando substituição de variável bash em vez de cut / awk

3

Posso usar a substituição de variáveis bash para extrair uma parte de uma variável baseada em um delimitador? Estou tentando obter o nome do diretório imediato de um nome de arquivo (neste caso, foo ).

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

Eu sei que posso fazer algo como

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

ou

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

mas está ficando lento para bifurcar awk / cut para vários nomes de arquivos.

Eu fiz um pequeno perfil das várias soluções, usando meus arquivos reais:

echo | corte:

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

echo | awk:

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

@ substituição de variáveis / expansão de parâmetros shell da steeldriver:

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

@ Disputas IFS do jai_s:

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

Ambas as sugestões foram uma grande melhoria em relação às minhas ideias existentes, mas a substituição de variáveis é mais rápida porque não requer nenhum processo novo.

    
por bonh 07.01.2016 / 14:47

4 respostas

10

Você pode remover a substring de entrelinha mais curta que corresponde a */

tmp="${filename#*/}"

e, em seguida, remova a substring posterior mais longa que corresponda a /*

echo "${tmp%%/*}"
    
por 07.01.2016 / 14:55
3
    echo $f
    a/b/c

    $ (IFS='/';set $f; echo $1)
     a

    $ (IFS='/';set $f; echo $2)
     b

    $ (IFS='/';set $f; echo $3)
     c

com curinga, parece funcionar com aspas duplas ou simples -

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

sim, você terá que desmarcar o IFS de volta ao padrão

    unset IFS
    
por 07.01.2016 / 15:11
1

Alimente a lista com awk para agilizar:

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

Demonstração:

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
    
por 07.01.2016 / 15:06
0

Por que você não usa o comando "dirname", em vez de todo esse material do awk / sed / cut?

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

Rendimentos:

./foo/bar
    
por 12.12.2017 / 22:21

Tags