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


25

/usr/bin/env sed -f터미널에서 입력하면 작동합니다.

그러나 그것을 세방으로 사용한다면

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

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

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

나는 그것이 -f와 관련이 있다고 생각합니다. 그러나 이것을 해결하는 방법?


답변:


33

이식 가능하게 하나 이상의 인수를 한 #!줄 에 넣을 수는 없습니다 . 이는 전체 경로와 하나의 인수 (예 : #!/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

heredoc의 단점은의 유용한 사용법으로 해결할 수 있습니다 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. 함수가 구문 적으로 잘 구성된 한 내용은 중요하지 않습니다 (특히 빈 함수를 가질 수 없음). 그런 다음 참이면 (즉, 항상) sed스크립트 에서 실행 하십시오.
  • sed 아래에서 : ()레이블로 분기 한 다음 올바른 형식의 입력. 그런 다음 i명령은 항상 건너 뛰기 때문에 효과가 없습니다. 마지막으로 ()레이블 뒤에 스크립트의 유용한 부분이 있습니다.
  • GNU sed, BusyBox 및 OpenBSD에서 테스트되었습니다. (GNU sed에서 더 간단한 것을 얻을 수는 있지만 OpenBSD sed는 건너 뛰는 부분에 대해 까다 롭습니다.)

1
"또는 #!/usr/bin/env논쟁이 없다." 잘 표현되지 않았습니다. 아마도 "또는 #!/usr/bin/env sedsed에 대한 논쟁이 없습니다."
CJM

:) "조금 못생긴"및 이중 언어 스크립트에 대한 한
retracile

6

OS에 따라 호환되지 않는 다양한 세방 (#!) 구현이 있습니다. 일부는 전체 인수 목록을 작성하고 일부는 명령 경로를 유지하고 나머지 모든 인수를 단일 인수로 배치하고 일부는 모든 인수를 무시하고 명령 경로 만 전달하며 일부는 전체 문자열을 단일로 전달합니다 명령. 후자의 경우 인 것 같습니다.


2

env가 "sed -f"라는 이름의 파일을 찾으려고합니다. "#! / usr / bin / sed -f"를 shebang 라인으로 시도 할 수 있습니다.


2

GNU coreutils v8.30 부터 다음을 수행 할 수 있습니다.

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

이 기능은 GNU coreutils 패키지에 최근 (2018-04-20) 커밋env.c추가되었으며 -Sor --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 매뉴얼에 있습니다 .

-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’

참고 : 이 경우에만 사용 shebangs 적용 /usr/bin/env으로, --split-stringGNU의 기능입니다 env특히.


1

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

  1. read 쉘 변수에 heredoc.
  2. 해당 변수를 위치 인수로에 전달하십시오 sed.

견본:

#!/usr/bin/env bash

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

exec sed "$SED_SCRIPT" "$@"

1

나는 Walker의 솔루션을 좋아하지만 개선 될 수 있습니다 (댓글은 미리 형식이 지정된 텍스트를 허용하지 않기 때문에 별도의 답변으로 작성). 모든 Linux 또는 Bash 버전에서는 작동하지 않을 수 있지만 Ubuntu 17.10에서는 다음과 같이 줄일 수 있습니다.

#!/usr/bin/env bash
read SED_SCRIPT <<EOD
s/a/b/
EOD
sed "$SED_SCRIPT" "$@"

명령을 제거하고 명령을 eval단순화 할 수 read있지만 heredoc 내에서 주석을 제거해야합니다.

또한 sed에 대해 알고 싶었지만 묻기를 두려워하는 모든 것에 대해 http://www.grymoire.com/unix/sed.html에 매우 유용한 자습서가 있습니다. 이것은 /usr/bin/envsed에 대한 경로를 잃고 하드 코딩하는 비용을 들이지 않고 더 나은 솔루션을 제안합니다 .

#!/bin/sed -f
s/a/b/
s/c/d/

이는 둘 이상의 s///교체 를 지원한다는 추가 이점이 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.