Eu tenho ± 10.000 arquivos ( res.1
- res.10000
), todos compostos por uma coluna e um número igual de linhas. O que eu quero é, em essência, simples; mesclar todos os arquivos em colunas em um novo arquivo final.res
. Eu tentei usar:
paste res.*
No entanto (embora este parece funcionar para um pequeno subconjunto de arquivos de resultados, isso dá o seguinte erro quando executada em todo o conjunto: Too many open files
.
Deve haver uma maneira 'fácil' de fazer isso, mas infelizmente sou novo no unix. Desde já, obrigado!
PS: Para ter uma idéia de como (um dos meus) arquivos de dados se parece:
0.5
0.5
0.03825
0.5
10211.0457
10227.8469
-5102.5228
0.0742
3.0944
...
command-line
text-processing
columns
paste
tapetes
fonte
fonte
--serial
opção com opaste
comando?paste --serial
não mescla arquivos coluna sábio ...paste -s
realmente funciona, mas cola os arquivos de resultados separados em linhas, em vez de em colunas. No entanto, isso é algo que posso resolver. Obrigado!Respostas:
Se você possui permissões de root nessa máquina, pode aumentar temporariamente o limite "número máximo de descritores de arquivos abertos":
E depois
Depois disso, você pode configurá-lo de volta aos valores originais.
Uma segunda solução , se você não pode alterar o limite:
Ele chama
paste
cada arquivo uma vez e, no final, existe um arquivo enorme com todas as colunas (leva um minuto).Edit : Uso inútil de gato ... Não !
Como mencionado nos comentários, o uso de
cat
here (cat final.res | paste - $f >temp
) não é inútil. A primeira vez que o loop é executado, o arquivofinal.res
ainda não existe.paste
falhará e o arquivo nunca será preenchido nem criado. Com a minha solução, apenascat
falha na primeira vezNo such file or directory
epaste
lê do stdin apenas um arquivo vazio, mas continua. O erro pode ser ignorado.fonte
ulimit -Sn
para o limite suave eulimit -Hn
para o limite rígido-bash: /usr/bin/paste: Argument list too long
. Idéias como resolver isso? Desculpe por incomodar vocês.getconf ARG_MAX
, você só pode aumentar esse valor ao recompilar o kernel. Você pode tentar minha segunda solução?cat
sempre o loop, você pode começar criando umfinal.res
arquivo vazio . Provavelmente, essa é uma boa ideia, caso jáfinal.res
exista um arquivo.Se a resposta do caos não for aplicável (porque você não possui as permissões necessárias), você pode agrupar as
paste
chamadas da seguinte maneira:Esta lista os arquivos 1000 em um momento em arquivos chamados
lists00
,lists01
etc., em seguida, cola os correspondentesres.
arquivos em arquivos chamadosmerge00
,merge01
etc., e, finalmente, funde-se todos os arquivos resultantes parcialmente fundidas.Conforme mencionado pelo caos, você pode aumentar o número de arquivos usados de uma só vez; o limite é o valor fornecido
ulimit -n
menos os arquivos que você já abriu, então você diriapara usar o limite menos dez.
Se a sua versão do
split
não suportar-d
, você poderá removê-lo:split
basta digitar o sufixo numérico. Por padrão, os sufixos seráaa
,ab
etc., em vez de01
,02
etc.Se houver tantos arquivos que
ls -1 res.*
falharem ("lista de argumentos muito longa"), você poderá substituí-lo pelofind
que evitará esse erro:(Como apontado por don_crissti ,
-1
não deve ser necessário quandols
a saída da tubulação ; mas estou deixando isso para lidar com casos em quels
há alias-C
.)fonte
Tente executá-lo desta maneira:
Você também pode dividir o lote em partes e tentar algo como:
e no final combine os arquivos finais
fonte
Too many open files
final.x00
canais "be" - ou como FIFOs nomeados, ou implicitamente, usando a substituição de processo (se o seu shell suportar - por exemplo, bash). Não é divertido escrever à mão, mas pode ser adequado a um makefile.Eu não acho que isso seja tão complicado quanto tudo isso - você já fez o trabalho duro ordenando os nomes dos arquivos. Só não abra todos eles ao mesmo tempo, é tudo.
Outra maneira:
... mas acho que isso é feito ao contrário ... Isso pode funcionar melhor:
E aqui está outra maneira:
Isso permite
tar
reunir todos os arquivos em um fluxo delimitado por nulo para você, analisa todos os metadados do cabeçalho, exceto o nome do arquivo, e transforma todas as linhas em todos os arquivos em guias. No entanto, ele depende da entrada como arquivos de texto reais - o que significa que cada um termina com uma nova linha e não há bytes nulos nos arquivos. Ah - e também conta que os nomes de arquivos são livres de novas linhas (embora isso possa ser tratado com robustez comtar
a--xform
opção do GNU ) . Dadas essas condições, ele deve fazer um trabalho muito curto de qualquer número de arquivos - etar
fará quase tudo.O resultado é um conjunto de linhas que se parecem com:
E assim por diante.
Eu testei criando primeiro 5 arquivos de teste. Eu realmente não estava com vontade de gerar 10000 arquivos agora, então fiquei um pouco maior para cada um - e também garanti que os comprimentos dos arquivos diferissem bastante. Isso é importante ao testar
tar
scripts, porquetar
bloqueará a entrada em comprimentos fixos - se você não tentar pelo menos alguns comprimentos diferentes, nunca saberá se realmente lidará com apenas um.Enfim, para os arquivos de teste que fiz:
ls
depois relatou:... então eu corri ...
... apenas para mostrar apenas os primeiros 25 campos delimitados por tabulação por linha (porque cada arquivo é uma única linha - há muito ) ...
A saída foi:
fonte
Dada a quantidade de arquivos, tamanhos de linha, etc. envolvidos, acho que ultrapassará o tamanho padrão das ferramentas (awk, sed, paste, *, etc)
Eu criaria um pequeno programa para isso, ele não teria 10.000 arquivos abertos, nem uma linha de centenas de milhares de comprimento (10.000 arquivos de 10 (tamanho máximo da linha no exemplo)). Requer apenas uma matriz de 10.000 números inteiros, para armazenar o número de bytes que foram lidos em cada arquivo. A desvantagem é que ele possui apenas um descritor de arquivo, é reutilizado para cada arquivo, para cada linha, e isso pode ser lento.
As definições de
FILES
eROWS
devem ser alteradas para os valores exatos reais. A saída é enviada para a saída padrão.fonte