Bash: maneira sucinta de fazer loop por linhas de stdin ou argumentos de linha de comando?

1

Eu tenho um script bash que eu gostaria de fazer um loop sobre as linhas em stdin, ou loop sobre cada argumento passado.

Existe uma maneira limpa de escrever isso, então eu não tenho que ter dois loops?

#!/bin/bash

# if we have command line args... 
if [ -t 0 ]
then
  # loop over arguments
  for arg in "$@" 
  do
    # process each argument
  done
else
  # loop over lines from stdin
  while IFS= read -r line; do
    # process each line
  done
fi

EDIT: Eu estou procurando uma solução genérica que usa apenas um único loop, como eu acho que eu quero fazer isso com bastante frequência, mas sempre escrevi 2 loops e, em seguida, chamou uma função em seu lugar. Então, talvez algo que transforme stdin em uma matriz, então eu poderia usar um único loop em vez disso?

    
por Brad Parks 23.03.2018 / 14:35

2 respostas

2

Crie dados para o seu loop while read :

#!/bin/sh

if [ "$#" -gt 0 ]; then
    # We have command line arguments.
    # Output them with newlines in-between.
    printf '%s\n' "$@"
else
    # No command line arguments.
    # Just pass stdin on.
    cat
fi |
while IFS= read -r; do
    printf 'Got "%s"\n' "$REPLY"
done

Observe que o seu exemplo concat pode ser feito com o loop while read substituído por tr '\n' ',' ou similar.

Além disso, o teste -t não diz nada sobre se você tem argumentos de linha de comando ou não.

Como alternativa, para processar os argumentos da linha de comando ambos e a entrada padrão (nessa ordem):

#!/bin/sh

{
    if [ "$#" -gt 0 ]; then
        # We have command line arguments.
        # Output them with newlines in-between.
        printf '%s\n' "$@"
    fi

    if [ ! -t 0 ]; then
        # Pass stdin on.
        cat
    fi
} |
while IFS= read -r; do
    printf 'Got "%s"\n' "$REPLY"
done

Ou, usando a notação curta que algumas pessoas parecem gostar:

#!/bin/sh

{
    [ "$#" -gt 0 ] && printf '%s\n' "$@"
    [ ! -t 0 ]     && cat
} |
while IFS= read -r; do
    printf 'Got "%s"\n' "$REPLY"
done
    
por 23.03.2018 / 16:01
1

Com bash especificamente, você poderia fazer:

if [ -t 0 ]; then
  args=("$@")
else
  readarray -t args
fi
for i in "${args[@]}"; do
   ...
done
    
por 23.03.2018 / 16:06

Tags