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

Posso usar a substituição de variável bash para extrair um pedaço de uma variável com base 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 poderia fazer algo como

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

ou

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

mas isso ” está ficando lento para bifurcar awk / cut para vários nomes de arquivo.

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

echo | cut:

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

echo | awk:

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

@steeldriver “s substituição de variável / expansão 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 as sugestões foram uma grande melhoria em relação às minhas ideias existentes, mas a substituição de variável é mais rápida porque não exigem a bifurcação de quaisquer novos processos.

Comentários

  • gnu.org/software/bash/manual / html_node / …
  • Envie todos os nomes de arquivos para uma invocação de awk e será significativamente mais rápido do que qualquer solução em bash puro
  • Você não pode usar uma matriz, fazer tudo de uma vez e depois colocá-la em uma nova matriz?

Resposta

Você pode remover a substring inicial mais curta que corresponda a */

tmp="${filename#*/}" 

e, em seguida, remover a mais longa substring final que corresponde a /*

Resposta

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

com o caractere curinga parece funcionar 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 restaurar o IFS para o padrão

 unset IFS 

Comentários

  • Ooh, eu gosto disso.
  • Este geralmente é meu método preferido também, mas tenha em mente que Bash suporta apenas $1 a $9 usando esta sintaxe. Para o 10º e os argumentos posteriores, o formato ${10} deve ser usado.
  • Não ' não funciona quando $f contém curingas. E você precisa restaurar IFS depois (ou fazer isso em uma substituição de comando, para obter o valor de um campo, e isso remove novas linhas finais).
  • O exemplo funciona isoladamente (dentro do Git bash no Windows), mas quando canalizo a partir do comando find, recebo este erro: echo: write error: Bad address.
  • Ok, parece que Tenho que unset IFS todas as vezes.

Responder

Feed a lista para awk para acelerá-la:

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 

Resposta

Por que você não usa o comando” dirname “, em vez de tudo isso awk / sed / cortar coisas?

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

Rendimentos:

./foo/bar 

Comentários

  • Neste caso, eu estava procurando o diretório imediato, não o caminho completo do diretório.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *