매개변수 또는 파이프의 입력을 허용하는 Bash 함수

매개변수 또는 파이프의 입력을 허용하는 Bash 함수

매개변수나 파이프로부터 입력을 받을 수 있는 방식으로 다음 bash 함수를 작성하고 싶습니다.

b64decode() {
    echo "$1" | base64 --decode; echo
}

필수 사용:

$ b64decode "QWxhZGRpbjpvcGVuIHNlc2FtZQo="
$ b64decode < file.txt
$ b64decode <<< "QWxhZGRpbjpvcGVuIHNlc2FtZQo="
$ echo "QWxhZGRpbjpvcGVuIHNlc2FtZQo=" | b64decode

답변1

바라보다Stefan Chazeras의 답변더 나은 솔루션을 얻으려면.


/dev/stdin다음을 사용하여 표준 입력에서 읽을 수 있습니다 .

b64decode()
{
    if (( $# == 0 )) ; then
        base64 --decode < /dev/stdin
        echo
    else
        base64 --decode <<< "$1"
        echo
    fi
}
  • $# == 0명령줄 인수 수가 0인지 확인하세요.
  • base64 --decode <<< "$1"사용 및 파이프 herestring대신 사용하는 것도 가능합니다.echobase64

답변2

여기에서는 다음과 같아야 합니다.

b64decode() {
  if [ "$#" -gt 0 ]; then
    # concatenated arguments fed via a pipe.
    printf %s "$@" | base64 --decode
  else
    base64 --decode  # read from stdin
  fi
  ret=$?
  echo # add one newline character
  return "$ret" # return with base64's exit status to report decoding
                # errors if any.
}

아무튼 하세요아니요사용 base64 --decode < /dev/stdin. 기껏해야 (대부분의 시스템에서) 아무것도 하지 않고 단지 (fd 0을 fd 0에 복사, 작업 없음) < /dev/stdin것과 동일한 작업을 수행합니다 .dup2(0,0)

그러나 Linux나 Cygwin에서는 < /dev/stdin이것이 제대로 작동하지 않습니다. 이러한 시스템에서 열기는 /dev/stdinstdin을 복사하는 것과 동일하지 않습니다. 처음부터 다시 열고 현재 stdin에 열려 있는 파일과 동일한 파일을 독립적으로 엽니다.

따라서 이전에 stdin이 일부 일반 파일의 중간을 가리키고 있었다면 나중에 < /dev/stdinstdin이 현재 가리키는 결과를 얻게 됩니다.처음에파일의. stdin이 파이프의 쓰기 끝(일반적인 상황에서는 있어서는 안 됨)인 경우 결국에는 읽기 끝이 됩니다. 소켓인 경우 소켓이 불가능하므로 실패합니다.열려 있는. 읽기 위해 파일을 열 수 있는 권한이 없는 경우에도 마찬가지입니다(예: 권한이 변경되었거나 파일이 원래 다른 자격 증명을 사용하여 stdin에서 열렸기 때문에).

반환 시 base64 --decode < /dev/stdin파일에서 stdin의 현재 위치(검색 가능한 파일 입력의 경우)는 끝(또는 base64읽기가 중지되는 위치)에 남아 있지 않고 변경되지 않은 상태로 유지됩니다. 왜냐하면 base64의 stdin이 다른 위치에 있기 때문입니다.파일 설명 열기.

답변3

샌딥의 답변base64이는 유틸리티가 여러 줄을 지원하지 않기 때문에 작동합니다 . 보다 일반적인 경우에 대한 보다 일반적인 수정 사항

그런가요?

my_function() {
    if (( ${#} == 0 )) ; then
        while read -r line ; do
            target_utility "${line}"
        done
    else
        target_utility "${@}"
    fi
}

답변4

둘 다샌딥의그리고톰 로치의대답은 계몽적이고 감사하지만 target_utility "${@}"상황에 따라 더 복잡한 코드를 나타낼 수 있습니다. if중요한 코드를 내부 및 외부로 복제하면 else불필요한 문제가 발생할 수 있습니다. OP의 질문이 재귀를 사용하여 완벽하게 해결되는 문제를 제시하지 못할 수도 있지만 다른 독자의 질문은 이를 사용하거나 래퍼 기능 사용을 고려하면 도움이 될 수 있습니다.

my_function() {
    if (( ${#} == 0 )) ; then
        while read -r __my_function ; do
            my_function "${__my_function}"
        done
    else
        target_utility "${@}"
    fi
}

이 답변은 "인수 또는 파이프의 입력을 허용하는 Bash 함수"에 대해 가능한 다양한 솔루션 중 하나입니다. OP가 [주석에서] 이것이 base64실제 문제 도메인이 아니라고 지적했기 때문입니다. 따라서 파일에서 직접 입력을 읽을 수 있는지 확인하려고 시도하지 않습니다.

다양한 의견에 따르면 이 템플릿 및 이와 유사한 다른 템플릿은 선행 공백이 있는 줄을 올바르게 처리하지 못할 수 있다는 우려가 IFS =있습니다 read. 실제로 쉘이 민감한 문자가 있으면 이 함수를 호출하기 전에 특별한 처리가 필요할 수 있습니다. 있는 그대로, 코드는 선행 공백이 발생하지 않는 것으로 알려져 있고 데이터 민감도가 이미터에 의해 사전 처리되는 경우 잘 작동합니다.

이것은 단지 교과서적인 예가 아닙니다. 실제 제작 스크립트에서 사용됩니다. target_utility실제 코드 조각의 간단한 이름입니다. 이 답변은 범용 템플릿을 가정하지 않으며 추가적인 개발자 지혜가 필요하지 않습니다.

(사용자가 일반적으로 답변을 그대로 사용하기보다는 때때로 답변을 조정할 것이라고 가정하는 것이 합리적으로 보입니다.)

관련 정보