Preciso alimentar um programa com alguns arquivos específicos, na ordem correta e agrupados dois a dois.
Se eu tiver
A_file.txt
B_file.txt
C_file.txt
D_file.txt
Preciso alimentá-lo em um programa para que os arquivos A e B sejam processados primeiro, depois C e D e assim por diante. Em essência:
for i in *.txt; do
some_program A_file.txt B_file.txt > output_AB
some_program C_file.txt D_file.txt > output_CD
Eu sei que o acima não faz sentido, mas foi para ilustrar o ponto. Essencialmente, repita todos .txt
os arquivos na pasta, mas alimente-os dois de cada vez no programa e, em seguida, passe para os próximos dois.
Olhando para aprender, muito obrigado.
Isso define os parâmetros posicionais para a lista de nomes de arquivo nos quais você está interessado, com base em um padrão de globbing de nome de arquivo correspondente aos nomes na pergunta. Em seguida, ele usa um loop para iterar sobre essa lista até que restem menos de dois nomes na lista (
$#
é o comprimento da lista de parâmetros posicionais).Em cada iteração, os dois primeiros elementos da lista,
$1
e$2
, são processados e então deslocados para fora da lista usandoshift 2
.A saída do processamento é redirecionada para um arquivo nomeado
output_
seguido pela concatenação das partes variáveis dos dois nomes de arquivo (o que estiver antes da_file.txt
string estática em cada um).Isso pressupõe que os arquivos sejam nomeados de forma que a classificação dos nomes em ordem lexicográfica (o que a expansão do padrão globbing fará) resulte em uma lista de nomes que podem ser emparelhados da maneira mostrada na pergunta.
Você poderia fazer isso com o
xargs
comando. Se eu tiver esses arquivos:Então eu posso processar esses dois ao mesmo tempo assim:
Aqui estou simplesmente chamando
echo
, mas é claro que você pode descartar oecho
e realmente executarsome_program
. Isso processará dois arquivos por vez... mas não lida com a geração de um nome de arquivo de saída para cada chamada.Se tornarmos um pouco mais elaborado, podemos gerar um arquivo com o nome do primeiro nome de arquivo de entrada:
Isso produzirá o arquivo
A_file.txt.output
paraA_file.txt
eB_file.txt
,C_File.txt.output
para o próximo par e assim por diante. Você pode ficar mais sofisticado com o nome do arquivo de saída aplicando várias transformações; por exemplo, para obter o nome do arquivo que você pediu em sua pergunta, você pode escrever:Isso gerará nomes de arquivos de saída
output_AB
,output_CD
, etc.Se mudar de bash para zsh for uma opção, então é só:
(N)
permite nullglob dessa expansão glob para não relatar um erro se não houver correspondência.Se houver um número ímpar de arquivos, a última execução será executada com o
$j
conjunto para a string vazia. Como o deixamos sem aspas no argumento parasome_program
, isso resultará em nenhum argumento correspondente a ser passado para ele. Substitua por"$j"
se preferir que um argumento vazio seja passado para ele nesse caso.A
*.txt
expansão estará em ordem alfabética; você pode alterar a ordem para o que quiser usando os qualificadoreso
,O
e/oun
glob .Para um número arbitrário de arquivos em cada iteração, em vez de apenas 2:
Ou usando
zargs
:Em
${(Mj[])array#?}
,${array#?}
retiraria o caractere inicial de cada elemento do array, mas comM
, o que éM
anexado é retornado. O resultado éj
unificado com nada ([]
), então você obtém uma string feita com o primeiro caractere de cada elemento.Despeje a lista de arquivos em uma matriz e leia a partir dela.
Se você tiver um número ímpar de arquivos, a solicitação
${arr[ $[$i+1] ]}
fornecerá silenciosamente uma string vazia. Cabe a você decidir o que fazer neste caso.