Bash: 표준 입력 또는 명령줄 인수의 줄을 반복하는 깔끔한 방법은 무엇입니까?

Bash: 표준 입력 또는 명령줄 인수의 줄을 반복하는 깔끔한 방법은 무엇입니까?

Bash 스크립트가 있고 stdin의 줄을 반복하거나 전달된 각 인수를 반복하고 싶습니다.

두 개의 루프를 가질 필요가 없도록 이것을 작성하는 깔끔한 방법이 있습니까?

#!/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

편집: 나는 이 작업을 자주 수행하고 싶지만 항상 2개의 루프를 작성한 다음 함수를 호출하기 때문에 단일 루프를 사용하는 일반적인 솔루션을 찾고 있습니다. 그렇다면 stdin을 배열로 변환하여 대신 단일 루프를 사용할 수 있을까요?

답변1

루프에 대한 데이터를 생성합니다 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 string; do
    printf 'Got "%s"\n' "$string"
done

concat루프를 또는 유사한 것으로 대체하여 예제를 수행할 수 있습니다.while readtr '\n' ','

또한 -t테스트에서는 명령줄 인수가 있는지 여부를 알려주지 않습니다.


아니면, 처리둘 다명령줄 인수 및 표준 입력(순서):

#!/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 string; do
    printf 'Got "%s"\n' "$string"
done

또는 일부 사람들이 좋아하는 단축 표기법을 사용하세요.

#!/bin/sh

{
    [ "$#" -gt 0 ] && printf '%s\n' "$@"
    [ ! -t 0 ]     && cat
} |
while IFS= read -r string; do
    printf 'Got "%s"\n' "$string"
done

답변2

표준 입력 리디렉션을 사용할 수도 있습니다.

#!/usr/bin/env bash
test -t 0 && exec < <(printf '%s\n' "$@")
while IFS= read -r line; do
    echo "$line"
done

시험:

test.sh Hello World
test.sh < /etc/passwd

답변3

구체적으로 bash다음과 같이 할 수 있습니다.

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

답변4

STDIN 설명자에 액세스하여 다음을 수행할 수도 있습니다.

for i in $(cat /dev/stdin) ; do echo $i ; done

관련 정보