Shebang에서 `/usr/bin/env sed -f`를 사용하는 방법은 무엇입니까?

Shebang에서 `/usr/bin/env sed -f`를 사용하는 방법은 무엇입니까?

/usr/bin/env sed -f터미널에 입력하면 유효합니다.

하지만 셔뱅이라고 생각한다면,

#!/usr/bin/env sed -f 
s/a/b/

스크립트가 실행되지 않습니다.

/usr/bin/env: sed -f: No such file or directory

나는 그것이 -f와 관련이 있다고 생각합니다. 하지만 이 문제를 어떻게 해결해야 할까요?

답변1

#!한 줄에 여러 매개변수를 넣을 수는 없습니다.. 이는 전체 경로와 하나의 인수(예: #!/bin/sed -f또는 #!/usr/bin/sed -f) 만 있거나 #!/usr/bin/env인터프리터에 대한 인수가 없음을 의미합니다.

이식 가능한 스크립트를 얻는 해결 방법은 쉘 래퍼를 사용 #!/bin/sh하고 sed 스크립트를 명령줄 인수로 전달하는 것입니다. 이는 POSIX 승인이 아니지만(이식성을 위해 다중 명령어 스크립트는 -e각 명령어에 대해 별도의 매개변수를 작성해야 함) 많은 구현에서 작동합니다.

#!/bin/sh
exec sed '
s/a/b/
' "$@"

긴 스크립트의 경우 heredoc을 사용하는 것이 더 편리할 수 있습니다. Heredoc의 한 가지 장점은 내부 작은따옴표(있는 경우)를 인용할 필요가 없다는 것입니다. 한 가지 주요 단점은 스크립트가 표준 입력을 통해 sed에 공급된다는 점이며, 이로 인해 두 가지 성가신 결과가 발생합니다. sed의 일부 버전에서는 -f /dev/stdin이를 대신 요구하는데 -f -, 이는 이식성에 문제가 됩니다. 게다가 표준 입력은 데이터가 아니라 스크립트이기 때문에 스크립트는 필터 역할을 할 수 없습니다.

#!/bin/sh
exec sed -f - -- "$@" <<'EOF'
s/a/b/
EOF

여기서 문서화의 단점은 효과적인 사용으로 보완될 수 있습니다 cat. 이는 전체 스크립트를 다시 명령줄에 배치하므로 POSIX와 호환되지 않지만 실제로는 이식성이 뛰어납니다.

#!/bin/sh
exec sed "$(cat <<'EOF')" -- "$@"
s/a/b/
EOF

또 다른 해결책은 sh 및 sed로 구문 분석할 수 있는 스크립트를 작성하는 것입니다. 이식성이 뛰어나고 상당히 효율적이지만 약간 추악합니다.

#! /bin/sh
b ()
{
x
}
i\
f true; then exec sed -f "$0" "$@"; fi
: ()
# sed script starts here
s/a/b/

설명하다:

  • sh 아래: 함수 b의 구문이 올바른 한(특히 빈 함수가 있을 수 없음)이라는 함수를 정의합니다. 내용은 중요하지 않습니다. 그런 다음 true(즉, 항상)이면 sed스크립트가 실행됩니다.
  • sed에서: ()레이블로 분기한 다음 올바른 형식의 입력을 입력합니다. 그런 다음 i항상 건너뛰므로 아무런 효과가 없는 명령이 있습니다 . 마지막으로 태그가 있고 ()그 뒤에 스크립트의 유용한 부분이 있습니다.
  • GNU sed, BusyBox 및 OpenBSD에서 테스트되었습니다. (GNU sed를 사용하면 더 간단한 것을 사용할 수 있지만 OpenBSD sed는 건너뛰는 부분이 까다롭습니다.)

답변2

GNU coreutils로 시작하기v8.30, 넌 할 수있어:

#!/usr/bin/env -S sed -f

이 기능은 최근 추가되었습니다 (2018-04-20)범죄또는 옵션이 env.c추가된 GNU coreutils 패키지 에 .-S--split-string

env매뉴얼 페이지 에서 :

OPTIONS
-S/--split-string usage in scripts
    The  -S  option allows specifing multiple parameters in a script.
    Running a script named 1.pl containing the following first line:

            #!/usr/bin/env -S perl -w -T

    Will execute perl -w -T 1.pl .

    Without the '-S' parameter the script will likely fail with:

            /usr/bin/env: 'perl -w -T': No such file or directory

    See the full documentation for more details.

더 많은 예는 다음에서 찾을 수 있습니다.GNU coreutils 매뉴얼.

verbose 출력 옵션도 사용하면 인수 문자열이 -v어떻게 분할되는지 정확하게 확인할 수 있습니다 .env

존재하다 my_sed_script.sed:

#!/usr/bin/env -vS sed -f
s/a/b/

구현하다:

$ ./my_sed_script.sed
split -S:  ‘sed -f’
 into:    ‘sed’
     &    ‘-f’
executing: sed
   arg[0]= ‘sed’
   arg[1]= ‘-f’
   arg[2]= ‘./my_sed_script.sed’

노트:이는 GNU의 특수 기능인 /usr/bin/envshebang 을 사용할 때만 작동합니다 .--split-stringenv

답변3

운영 체제에 따라 shebang(#!)의 호환되지 않는 다양한 구현이 있습니다. 일부는 전체 인수 목록을 작성하고, 일부는 명령 경로를 유지하고 나머지 모든 인수를 단일 인수로 전달하고, 일부는 모든 인수를 무시하고 명령 경로만 전달하고, 마지막으로 일부는 전체 문자열을 명령에 전달합니다. 단일 인수. 당신은 후자의 상황에 있는 것 같습니다.

답변4

이 답변은 우아한 솔루션에 대한 경로를 제공합니다.https://stackoverflow.com/a/1655389/642372

  1. read구분 기호를 쉘 변수에 넣으십시오.
  2. 이 변수를 위치 인수로 에 전달합니다 sed.

견본:

#!/usr/bin/env bash

read -rd '' SED_SCRIPT <<EOD      
# Your sed script goes here.
s/a/b/
EOD

exec sed "$SED_SCRIPT" "$@"

관련 정보