AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 426748
Accepted
sodiumnitrate
sodiumnitrate
Asked: 2018-02-27 09:25:17 +0800 CST2018-02-27 09:25:17 +0800 CST 2018-02-27 09:25:17 +0800 CST

cat um número muito grande de arquivos juntos na ordem correta

  • 772

Eu tenho cerca de 15.000 arquivos nomeados file_1.pdb, file_2.pdb, etc. Posso agrupar alguns milhares deles fazendo:

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 vi esse problema sendo resolvido fazendo, find . -name xx -exec xxmas isso não preservaria a ordem com a qual os arquivos são unidos. Como posso conseguir isso?

files find
  • 6 6 respostas
  • 12673 Views

6 respostas

  • Voted
  1. Best Answer
    Kusalananda
    2018-02-27T09:33:16+08:002018-02-27T09:33:16+08:00

    Usando find, sorte xargs:

    find . -maxdepth 1 -type f -name 'file_*.pdb' -print0 |
    sort -zV |
    xargs -0 cat >all.pdb
    

    O findcomando encontra todos os arquivos relevantes e, em seguida, imprime seus nomes de caminho para sortfazer uma "classificação de versão" para colocá-los na ordem correta (se os números nos nomes de arquivo tivessem sido preenchidos com zero em uma largura fixa, não precisaríamos -V). xargspega essa lista de nomes de caminhos classificados e os executa catem lotes tão grandes quanto possível.

    Isso deve funcionar mesmo se os nomes dos arquivos contiverem caracteres estranhos, como novas linhas e espaços. Usamos -print0with findpara fornecer sortnomes terminados em nul para classificar e sortos manipulamos usando -z. xargstambém lê nomes terminados em nul com seu -0sinalizador.

    Observe que estou escrevendo 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 pelo OpenBSD e pela implementação do macOS.

    Os sinalizadores não padronizados usados ​​são

    • -maxdepth 1, para findinserir apenas o diretório superior, mas nenhum subdiretório. Positivamente, usefind . ! -name . -prune ...
    • -print0, para criar findnomes de caminho com terminação nula (isso foi considerado pelo POSIX, mas rejeitado). Pode-se usar -exec printf '%s\0' {} +em vez disso.
    • -z, para fazer sortregistros com terminação nula. Não há equivalência POSIX.
    • -V, para sortclassificar, por exemplo , 200após 3. Não há equivalência POSIX, mas pode ser substituído por uma classificação numérica em partes específicas do nome do arquivo se os nomes dos arquivos tiverem um prefixo fixo.
    • -0, para fazer xargsregistros lidos com terminação nula. Não há equivalência POSIX. Positivamente, seria necessário citar os nomes dos arquivos em um formato reconhecido por xargs.

    Se os nomes de caminho forem bem comportados e se a estrutura do diretório for plana (sem subdiretórios), pode-se fazer sem esses sinalizadores, exceto -Vcom sort.

    • 53
  2. Stéphane Chazelas
    2018-02-27T09:52:09+08:002018-02-27T09:52:09+08:00

    Com zsh(de onde {1..15000}vem esse operador):

    autoload zargs # best in ~/.zshrc
    zargs file_{1..15000}.pdb -- cat > file_all.pdb
    

    Ou para todos os file_<digits>.pdbarquivos em ordem numérica:

    zargs file_<->.pdb(n) -- cat > file_all.pdb
    

    (onde <x-y>é um operador glob que corresponde a números decimais x a y. Com nenhum xnem y, é qualquer número decimal. Equivalente a extendedglob's [0-9]##ou kshglob's +([0-9])(um ou mais dígitos)).

    Com ksh93, usando seu catcomando interno (portanto, não afetado por esse limite da execve()chamada do sistema, pois não há execução ):

    command /opt/ast/bin/cat file_{1..15000}.pdb > file_all.pdb
    

    Com bash/ zsh/ ksh93(que suportam zshe {x..y}possuem printfbuilt-in):

    printf '%s\n' file_{1..15000}.pdb | xargs cat > file_all.pdb
    

    Em um sistema GNU ou compatível, você também pode usar seq:

    seq -f 'file_%.17g.pdb' 15000 | xargs cat > file_all.pdb
    

    Para as xargssoluções baseadas em -, deve-se tomar cuidado especial com nomes de arquivo que contenham espaços em branco, aspas simples ou duplas ou barras invertidas.

    Como para -It's a trickier filename - 12.pdb, use:

    seq -f "\"./-It's a trickier filename - %.17g.pdb\"" 15000 |
      xargs cat > file_all.pdb
    
    • 14
  3. OmnipotentEntity
    2018-02-27T10:54:23+08:002018-02-27T10:54:23+08:00

    Um loop for é possível e muito simples.

    for i in file_{1..15000}.pdb; do cat $i >> file_all.pdb; done
    

    A desvantagem é que você invoca catum monte de vezes. Mas se você não consegue se lembrar exatamente como fazer as coisas finde a sobrecarga de invocação não é tão ruim em sua situação, vale a pena ter isso em mente.

    • 12
  4. LarryC
    2018-02-27T12:12:00+08:002018-02-27T12:12:00+08:00
    seq 1 15000 | awk '{print "file_"$0".dat"}' | xargs cat > file_all.pdb
    
    • 3
  5. Hastur
    2018-02-28T03:08:57+08:002018-02-28T03:08:57+08:00

    Premissa

    Você não deve incorrer nesse erro apenas para arquivos de 15k com esse formato de nome específico [ 1 , 2 ] .

    Se você estiver executando essa expansão de outro diretório e tiver que adicionar o caminho para cada arquivo, o tamanho do seu comando será maior e é claro que isso pode ocorrer.

    Solução , execute o comando desse diretório.

    (cd That/Directory ; cat file_{1..2000}.pdb >> file_all.pdb )
    

    Melhor solução Se, em vez disso, eu adivinhei mal e você o executa a partir do diretório em que os arquivos estão ...
    IMHO, a melhor solução é a de Stéphane Chazelas :

    seq -f 'file_%.17g.pdb' 15000 | xargs cat > file_all.pdb
    

    com printf ou seq; testado em arquivos de 15k com apenas seu número dentro do pré-cache, é ainda o mais rápido (no momento e exceto o OP do mesmo diretório em que os arquivos estão).

    Algumas palavras mais

    Você deve ser capaz de passar para as linhas de comando do shell por mais tempo.
    Sua linha de comando tem 213.914 caracteres e contém 15.003 palavras
    cat file_{1..15000}.pdb " > file_all.pdb" | wc

    ...mesmo adicionando 8 bytes para cada palavra é 333.938 bytes (0,3M) muito abaixo do 2097142 (2,1M) relatado por ARG_MAXem um kernel 3.13.0 ou o ligeiramente menor 2088232 relatado como "Comprimento máximo do comando que poderíamos realmente usar" porxargs --show-limits

    Dê uma olhada em seu sistema para a saída de

    getconf ARG_MAX
    xargs --show-limits
    

    Solução guiada por preguiça

    Em casos como este prefiro trabalhar com blocos até porque costuma sair 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 para mim.
    Somente depois de verificar se a saída está correta, redireciono-a para um script.

    ... mas a preguiça é um estado de espírito .
    Como sou alérgico a xargs(realmente deveria ter usado xargsaqui) e não quero verificar como usar, pontualmente termino de 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

    #!/bin/bash
    StartN=${1:-1}          # First file number
    EndN=${2:-15000}        # Last file number
    BlockN=${3:-100}        # files in a Block 
    OutFile=${4:-"all.pdb"} # Output file name
    
    CurrentStart=$StartN 
    for i in $(seq $StartN $BlockN $EndN)
    do 
      CurrentEnd=$i ;  
        cat $(seq -f file_%.17g.pdb $CurrentStart $CurrentEnd)  >> $OutFile;
      CurrentStart=$(( CurrentEnd + 1 )) 
    done
    # Here you may need to do a last iteration for the part cut from seq
    [[ $EndN -ge $CurrentStart ]] && 
        cat $(seq -f file_%.17g.pdb $CurrentStart $EndN)  >> $OutFile;
    

    Versão 2

    Chamando o bash para a expansão (um pouco mais lento nos meus testes ~ 20%).

    #!/bin/bash
    StartN=${1:-1}          # First file number
    EndN=${2:-15000}        # Last file number
    BlockN=${3:-100}        # files in a Block 
    OutFile=${4:-"all.pdb"} # Output file name
    
    CurrentStart=$StartN 
    for i in $(seq $StartN $BlockN $EndN)
    do 
      CurrentEnd=$i ;
        echo  cat file_{$CurrentStart..$CurrentEnd}.pdb | /bin/bash  >> $OutFile;
      CurrentStart=$(( CurrentEnd + 1 )) 
    done
    # Here you may need to do a last iteration for the part cut from seq
    [[ $EndN -ge $CurrentStart ]] && 
        echo  cat file_{$CurrentStart..$EndN}.pdb | /bin/bash  >> $OutFile;
    

    Claro que você pode ir em frente e se livrar completamente de seq [ 3 ] (do coreutils) e trabalhar diretamente com as variáveis ​​no bash, ou usar python, ou compilar um programa ac para fazer isso [ 4 ] ...

    • 2
  6. glglgl
    2018-02-28T06:51:16+08:002018-02-28T06:51:16+08:00

    Outra forma de fazer pode ser

    (cat file_{1..499}.pdb; cat file_{500..999}.pdb; cat file_{1000..1499}.pdb; cat file_{1500..2000}.pdb) >> file_all.pdb
    
    • 0

relate perguntas

  • verificando se existe uma pasta em determinado diretório

  • Localizar e substituir cores em arquivos CSS na linha de comando

  • Como encontrar tipos de arquivos específicos e tar-los?

  • GNU find: obtenha caminho absoluto e relativo em -exec

  • du/df e ls relatando diferentes usos de disco

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    ssh Não é possível negociar: "nenhuma cifra correspondente encontrada", está rejeitando o cbc

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    Como descarregar o módulo do kernel 'nvidia-drm'?

    • 13 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add retorna com: "Erro ao conectar ao agente: nenhum arquivo ou diretório" 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya Por que o Linux usa LF como caractere de nova linha? 2017-12-20 05:48:21 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve