Eu tenho cerca de 15.000 arquivos nomeados file_1.pdb
, file_2.pdb
etc. Eu posso criar alguns milhares deles em ordem, fazendo o seguinte:
cat file_{1..2000}.pdb >> file_all.pdb
No entanto, se eu fizer isso para 15.000 arquivos, recebo o erro
-bash: /bin/cat: Argument list too long
Eu já vi esse problema sendo resolvido, find . -name xx -exec xx
mas isso não preservaria a ordem em que os arquivos foram adicionados. Como posso conseguir isso?
files
find
cat
brace-expansion
nitrato de sódio
fonte
fonte
cat file_{1..15000}.pdb
construção funciona bem para mim.getconf ARG_MAX
Deveria dizer.Respostas:
Usando
find
,sort
exargs
:O
find
comando localiza todos os arquivos relevantes e, em seguida, imprime seus nomes de caminho parasort
que eles façam uma "classificação de versão" para obtê-los na ordem correta (se os números nos nomes de arquivos tivessem sido preenchidos com zero a uma largura fixa, não precisaríamos-V
).xargs
pega essa lista de nomes de caminhos classificados e os executacat
em lotes tão grandes quanto possível.Isso deve funcionar mesmo que os nomes de arquivos contenham caracteres estranhos, como novas linhas e espaços. Nós usamos
-print0
comfind
para darsort
nomes com terminação nula para classificar esort
manipula-os usando-z
.xargs
também lê nomes terminados em nulo com seu-0
sinalizador.Observe que estou gravando o resultado em um arquivo cujo nome não corresponde ao padrão
file_*.pdb
.A solução acima usa alguns sinalizadores não padrão para alguns utilitários. Eles são suportados pela implementação GNU desses utilitários e, pelo menos, pela implementação do OpenBSD e do macOS.
Os sinalizadores não padrão usados são
-maxdepth 1
, parafind
inserir apenas o diretório mais alto, mas sem subdiretórios. POSIXly, usefind . ! -name . -prune ...
-print0
, para criarfind
nomes de caminho com terminação nula (isso foi considerado pelo POSIX, mas rejeitado). Pode-se usar em seu-exec printf '%s\0' {} +
lugar.-z
, para criarsort
registros com terminação nula. Não há equivalência POSIX.-V
, parasort
ordenar, por exemplo,200
depois3
. Não há equivalência POSIX, mas pode ser substituída por uma classificação numérica em partes específicas do nome do arquivo se os nomes de arquivos tiverem um prefixo fixo.-0
, para fazerxargs
registros com terminação nula. Não há equivalência POSIX. POSIX, seria necessário citar os nomes dos arquivos em um formato reconhecido porxargs
.Se os nomes de caminho forem bem comportados, e se a estrutura de diretórios for plana (sem subdiretórios), seria possível se contentar com esses sinalizadores, exceto
-V
comsort
.fonte
printf ‘file_%d.pdb\0’ {1..15000} | xargs -0 cat
, ou mesmo com o argumento de Kevinecho file_{1..15000}.pdb | xargs cat
. Afind
solução tem uma sobrecarga consideravelmente maior, pois precisa procurar esses arquivos no sistema de arquivos, mas é mais útil quando alguns dos arquivos podem não existir.xargs
vezcat
disso, é redirecionado (cadacat
chamada usará axargs
saída padrão). Se tivéssemos ditoxargs -0 sh -c 'cat >all.pdb'
, teria feito sentido usar em>>
vez de>
, se é isso que você está sugerindo.sort -n -k1.6
que funcionaria (para o original,file_nnn
nomes de arquivos ousort -n -k1.5
para aqueles sem o sublinhado).Com
zsh
(de onde esse{1..15000}
operador vem):Ou para todos os
file_<digits>.pdb
arquivos em ordem numérica:(onde
<x-y>
é um operador glob que corresponde aos números decimais x a y. Semx
nemy
, é qualquer número decimal. Equivalente aextendedglob
's '[0-9]##
oukshglob
's+([0-9])
(um ou mais dígitos)).Com
ksh93
, usando seucat
comando embutido (para não ser afetado por esse limite deexecve()
chamada do sistema, pois não há execução ):Com
bash
/zsh
/ksh93
(que suportezsh
's{x..y}
e têmprintf
embutido):Em um sistema GNU ou compatível, você também pode usar
seq
:Para as
xargs
soluções baseadas, seria necessário um cuidado especial com os nomes de arquivos que contêm espaços em branco, aspas simples ou duplas ou barras invertidas.Como para
-It's a trickier filename - 12.pdb
, use:fonte
seq -f | xarg cat >
é a solução mais elegante e eficaz. (NA MINHA HUMILDE OPINIÃO).'"./-It'\''s a trickier filename - %.17g.pdb"'
?Um loop for é possível e muito simples.
A desvantagem é que você invoca
cat
muitas vezes. Mas se você não consegue se lembrar exatamente de como fazer as coisasfind
e a sobrecarga de invocação não é muito ruim em sua situação, vale a pena lembrar.fonte
echo $i;
no corpo do laço como um "indicador de progresso"fonte
seq -f file_%.10g.pdb 15000
. Observe queseq
não é um comando padrão.seq -f
é uma ótima maneira de fazer isso; vai se lembrar disso.Premissa
Você não deve incorrer nesse erro em apenas 15k arquivos com esse formato de nome específico [ 1 , 2 ] .
Se você estiver executando essa expansão em outro diretório e precisar adicionar o caminho a cada arquivo, o tamanho do seu comando será maior e, é claro, pode ocorrer.
Solução execute o comando desse diretório.
Melhor solução Se, em vez disso, eu adivinhei mal e você o executou no diretório em que os arquivos estão ...
IMHO, a melhor solução é a de Stéphane Chazelas :
com printf ou seq; testado em arquivos de 15k com apenas seu número pré-armazenado em cache, é ainda o mais rápido (atualmente e exceto o OP do mesmo diretório em que os arquivos estão).
Algumas palavras mais
Você deve poder passar para as linhas de comando do shell por mais tempo.
Sua linha de comando tem 213914 caracteres e contém 15003 palavras
cat file_{1..15000}.pdb " > file_all.pdb" | wc
... mesmo adicionar 8 bytes para cada palavra é 333 938 bytes (0,3M) muito abaixo dos 2097142 (2,1M) relatados
ARG_MAX
no kernel 3.13.0 ou do 2088232 um pouco menor relatado como "Comprimento máximo de comando que poderíamos realmente use " porxargs --show-limits
Dê uma olhada no seu sistema para obter a saída de
Solução guiada por preguiça
Em casos como esse, prefiro trabalhar com blocos, mesmo porque geralmente são uma solução eficiente em termos de tempo.
A lógica (se houver) é que estou com preguiça de escrever 1 ... 1000 1001..2000 etc etc ...
Então, peço a um script que faça isso por mim.
Somente depois de verificar a saída, a correção é redirecionada para um script.
... mas a preguiça é um estado de espírito .
Como sou alérgico a
xargs
(eu realmente deveria ter usadoxargs
aqui) e não quero verificar como usá-lo, termino pontualmente para reinventar a roda, como nos exemplos abaixo (tl; dr).Observe que, como os nomes dos arquivos são controlados (sem espaços, novas linhas ...), você pode usar facilmente algo como o script abaixo.
tl; dr
Versão 1: passe como parâmetro opcional o 1º número do arquivo, o último, o tamanho do bloco, o arquivo de saída
Versão 2
Chamando bash para a expansão (um pouco mais lento nos meus testes ~ 20%).
Claro que você pode seguir em frente e se livrar completamente de
seq
[ 3 ] (do coreutils) e trabalhar diretamente com as variáveis no bash, usar python ou compilar um programa ac para fazê-lo [ 4 ] ...fonte
%g
é a abreviação de%.6g
. Representaria 1.000.000 como 1e + 06, por exemplo.xargs
, como zshzargs
ouksh93
'scommand -x
.seq
não é um bash embutido, é um comando do GNU coreutils.seq -f %g 1000000 1000000
produz 1e + 06 mesmo na versão mais recente do coreutils.xarg
... mas eu entendo que é pessoal e talvez relacionado apenas a mim.Outra maneira de fazer isso pode ser
fonte