Passar múltiplos argumentos de linha de comando para um executável com arquivos de texto

3

Eu tenho um executável C que aceita 4 argumentos de linha de comando.

program <arg1> <arg2> <arg3> <arg4>

Gostaria de criar um script de shell que execute continuamente o executável com argumentos fornecidos por arquivos de texto. A ideia seria algo assim:

./program "$(< arg1.txt)" "$(< arg2.txt)" "$(< arg3.txt)" "$(< arg4.txt)"

Onde os argumentos fornecidos para a execução n estariam na linha n de cada um dos arquivos. Quando tentei fazer isso, as chamadas printf () estavam interferindo umas nas outras ou em algum outro negócio engraçado acontecendo. Eu também estaria aberto para um script que leva apenas um arquivo onde os argumentos são delimitados de alguma forma.

    
por Eric Hou 18.10.2016 / 19:45

4 respostas

3
while 
  IFS= read -r a1 <&3 &&
    IFS= read -r a2 <&4 &&
    IFS= read -r a3 <&5 &&
    IFS= read -r a4 <&6
do
  ./program "$a1" "$a2" "$a3" "$a4" 3<&- 4<&- 5<&- 6<&-
done 3< arg1.txt 4< arg2.txt 5< arg3.txt 6< arg4.txt

Isso executa o loop até que um dos arquivos esteja esgotado. Substitua o && s por || s para executá-lo até que todos os arquivos estejam esgotados (usando argumentos vazios para arquivos menores).

Com o GNU xargs , você também pode fazer:

paste -d '\n' arg[1-4].txt | xargs -n 4 -r -d '\n' ./program

(embora tenha cuidado, o stdin de ./program seria, então, /dev/null )

    
por 18.10.2016 / 22:03
1

Confira uma combinação do comando sed e do comando paste. Primeiro, use o colar para criar um novo fluxo consistindo em todos os quatro arquivos. Em seguida, use sed para escolher a linha desejada:

paste arg1.txt arg2.txt arg3.txt arg4.txt | sed -n 10p

imprimirá a linha 10 da saída da pasta. Isso pode ser alimentado para o programa como argumentos usando xargs:

paste arg1.txt arg2.txt arg3.txt arg4.txt | sed -n 10p | xargs ./program

Se você quiser fazer um loop nas linhas, use o comando seq para gerar uma sequência e, em seguida, itere sobre cada valor na sequência:

for i in $(seq 1 100); do 
    paste arg1.txt arg2.txt arg3.txt arg4.txt | sed -n ${i}p | xargs ./program
done

Esse loop será lento, já que ele chama colar uma vez para cada iteração. Provavelmente é uma boa ideia criar primeiro um arquivo temporário.

    
por 18.10.2016 / 20:39
0

A melhor opção é pré-ler os arquivos e armazenar os resultados organizados em arrays ou arquivos temporários. Caso contrário, você terá que chamar as funções de leitura quatro vezes para cada iteração e fazer com que a função leia mais e mais adiante nos arquivos. Isso está longe de ser ótimo.

Esta é uma versão de arquivos temporários. Cuidado, não foi testado.

PROG=./program
TEMPDIR=tmp
mkdir "$TEMPDIR"

# Create the temp files.
for arg in arg*.txt; do
    i=0
    while read a; do
        ((i++))
        printf "%s\n" "$a" >> "$TEMPDIR"/"$i"
    done < "$arg"
done

# Now the temp files are ready.
## Each file contains all arguments for 1 run of ./program,
## each of them on a separate line.

# Start executing the ./program.
for iteration in "$(ls "$TEMPDIR" | sort -n)"; do
    unset args
    while read arg; do
        args=( "$arg" )
    done < "$TEMPDIR"/"$iteration"
    "$PROG" "${args[@]}"
done

# Finally, remove the temp files.
rm -r "$TEMPDIR"
    
por 18.10.2016 / 21:05
0

No Bash (ou algum outro shell que suporta $'' e matrizes), isso deve ser feito, desde que seus arquivos de entrada não contenham guias (*) :

IFS=$'\t'
paste arg1.txt arg2.txt | 
while read -r -a A ; do 
   [ "${#A[@]}" -eq 2 ] && printf "%s - %s\n" ${A[@]}
done 

paste une os arquivos de entrada linha por linha, read -a A lê as colunas para a matriz A , usando a guia (de IFS ) como um separador. [ "${#A[@]}" -eq 2 ] verifica se a matriz possui exatamente dois membros e ${A[@]} os descarta na linha de comando de printf . Altere o comando conforme necessário.

(* se você precisar dar suporte a guias, eu passaria a usar, por exemplo, Perl)

Com esses arquivos de entrada:

$ cat arg1.txt 
foo bar
doo
$ cat arg2.txt 
one
two two
three three three

A saída do snippet acima é:

foo bar - one
doo - two two

A última linha de arg2.txt é ignorada, pois arg1.txt não possui uma linha correspondente. read ignora as guias principais, impossibilitando o uso se nos preocuparmos com quais colunas tinham os elementos ausentes.

    
por 18.10.2016 / 21:38