
/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
#!
1行に複数のパラメータを含めることはできません。。これは、フルパスと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の1つの利点は、内部単一引用符(存在する場合)を引用する必要がないことです。 1つの主な欠点は、スクリプトが標準入力を介してsedに供給されることです。これは2つの迷惑な結果を引き起こします。 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/env
shebangを使用している場合にのみ機能します。--split-string
env
答え3
オペレーティングシステムによっては、shebang(#!)の互換性のないさまざまな実装があります。一部は完全な引数リストを作成し、一部はコマンドパスを保持し、残りのすべての引数を単一の引数として渡し、一部はすべての引数を無視してコマンドパスのみを渡し、最後に一部は文字列全体をコマンドに渡します。単一引数あなたは後者の状況にあるようです。
答え4
この答えはエレガントなソリューションへのパスを提供します。https://stackoverflow.com/a/1655389/642372
read
区切り文字をシェル変数に入れます。- この変数を位置引数としてに渡します
sed
。
サンプル:
#!/usr/bin/env bash
read -rd '' SED_SCRIPT <<EOD
# Your sed script goes here.
s/a/b/
EOD
exec sed "$SED_SCRIPT" "$@"