Em relação à expansão glob possivelmente excedendo um limite - sim e não. A concha já está funcionando e não vai parar. Mas se você passasse toda a matriz globbed como argumentos para um único comando, então sim, essa é uma possibilidade definida. A maneira portátil e robusta de lidar com isso envolve find ...
find . \! -name . -prune -name pattern -type f -exec cat {} + | ...
... que só irá cat dos arquivos regulares no diretório atual com um nome que corresponda a pattern , mas também invocará apenas cat quantas vezes forem necessárias para evitar excedendo ARG_MAX .
Na verdade, como você tem um GNU sed , nós podemos quase fazer a coisa toda com apenas sed em um script find .
cd /path/to/xmls
find . \! -name . -prune -name \*.xml -type f -exec \
sed -sne'1F;$x;/\n*\( \)*<\/*double>/!d' \
-e '$s///gp;H' {} + | paste -d\0 - -
Eu pensei em outro jeito. Isso será muito rápido, mas isso depende absolutamente de haver exatamente 168 correspondências por arquivo, e só pode haver um . dot nos nomes de arquivo.
( export LC_ALL=C; set '' - -
while [ "$#" -lt 168 ]; do set "$@$@"; done
shift "$((${#}-168))"
find . \! -name . -prune -name \*.xml -type f \
-exec grep -F '<double>' /dev/null {} + |
tr \<: '>>' | cut -d\> -f1,4 | paste -d\ "$@" |
sed 'h;s|./[^>]*>||g;x;s|\.x.*||;s|..||;G;s|\n| |'
)
Conforme solicitado, aqui está um pequeno resumo de como esse comando funciona:
-
( ... )- Em primeiro lugar, todo o pequeno script é executado dentro de sua própria sub-camada porque existem algumas propriedades ambientais globais que estaremos alterando no decorrer de sua execução, e assim, quando o trabalho é executado, todas as as propriedades que alteramos serão restauradas para seus valores originais - quaisquer que fossem elas.
-
%código%
- Ao definir a localidade atual como
export LC_ALL=C; set '' - -, podemos economizar muito esforço em nossos filtros. Em um código de idioma UTF-8, qualquer caractere pode ser representado por um ou vários bytes por peça, e qualquer caractere encontrado precisará ser selecionado de um grupo de muitos milhares de possíveis. Na localidade C, cada caractere é um único byte e há apenas 128 deles. Isso faz com que o char corresponda a um assunto muito mais rápido no geral. - A instrução
Caltera os parâmetros posicionais do shell. Fazendosetconjuntosset '' - -a$1ee$2$3a-.
- Ao definir a localidade atual como
-
%código%
- Basicamente, o objetivo dessa declaração é obter uma matriz de 168 traços. Usaremos
while ... set "$@$@"; done; shift ...depois para substituir conjuntos sequenciais de 167 novas linhas por espaços, preservando o 168º. A maneira mais simples de fazer isso é dar 168 referências de argumento parapastestdin e dizer para colar todas juntas.
- Basicamente, o objetivo dessa declaração é obter uma matriz de 168 traços. Usaremos
-
%código%
- O
-bit foi discutido anteriormente, mas comfind ... -exec grep -F '<double>' /dev/null' ...imprimimos apenas as linhas que podem ser comparadas com afindixed stringgrep. Ao tornar o primeiro argumento-F<double>- que é um arquivo que pode nunca corresponder a nossa string - garantimos quegrepesteja sempre pesquisando 2 ou mais argumentos de arquivo para cada chamada. Quando invocado com 2 ou mais arquivos de pesquisa nomeados,/dev/nullsempre imprimirá o nome do arquivo comogrepna cabeça de cada linha de saída.
- O
-
%código%
- Aqui, traduzimos cada ocorrência na saída de
grepdos caracteresfile_000.xml:outr \<: '>>'paragrep. - Nesse ponto, uma amostra da linha correspondente será parecida com
:.
- Aqui, traduzimos cada ocorrência na saída de
-
%código%
-
<removerá de sua saída toda a sua entrada que não pode ser encontrada no primeiro ou no quarto campo dividido por>chars. - Nesse ponto, uma amostra da linha correspondente será parecida com
./file_000.xml> >double>0.0000>/double>.
-
-
%código%
- Já discutimos, mas aqui estamos
cut -d\> -f1,4linhas de entrada em lotes de 168. - Nesse momento, 168 linhas correspondentes ocorrem juntas, como:
cut
- Já discutimos, mas aqui estamos
-
%código%
- Agora, os utilitários mais rápidos e menores já fizeram a maior parte do trabalho. Em um sistema multicore, eles provavelmente até fizeram isso concorrentemente. E esses utilitários - especialmente
>e./file_000.xml>0.0000são muito mais rápidos no que eles fazem do que qualquer tentativa de emulação que poderíamos fazer com utilitários de nível superior comopaste -d\ "$@"ou, pior ainda,% código%. Mas eu levei isso até onde eu posso imaginar até agora, e eu tenho que chamarpaste. - Primeiro, eu
./file_000.xml>0.000 .../file_000.xml>0.167old uma cópia de cada linha de entrada, então eused 'h;s|./[^>]*>||g;x;s|\.xml.*||;s|..||;G;s|\n| |'lobally remove todas as ocorrências do padrãocutno espaço de padrão - portanto, toda ocorrência do nome do arquivo. Neste ponto, o espaço padrão depasteé semelhante a:sed - Em seguida, eu e
awkchangesedespaços antigos e padrão e removo tudo dehon - então tudo a partir do primeiro nome de arquivo na cópia salva da linha. Eu então retiro os dois primeiros caracteres - ougtambém - e neste ponto o espaço padrão parece com./[^>]*>. - Então tudo o que resta é colocá-los juntos. Eu
sedet uma cópia de0.000 0.0001...0.167old espaço acrescentado ao espaço padrão seguindo um caracterexewline, então euhubstitute o\.xml.*ewline para um espaço. - Por fim, o espaço padrão é semelhante a
./. E é isso quefile_000grava na saída para cada arquivoGpassa parah.
- Agora, os utilitários mais rápidos e menores já fizeram a maior parte do trabalho. Em um sistema multicore, eles provavelmente até fizeram isso concorrentemente. E esses utilitários - especialmente