回答:
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を使用する方が便利な場合があります。ヒアドキュメントの利点は、内部に単一引用符がある場合でも引用符で囲む必要がないことです。主な欠点は、スクリプトが標準入力でsedに送られることで、2つの厄介な結果が生じます。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の両方で解析できるスクリプトを作成することです。これは移植性があり、適度に効率的で、少しlittleいです。
#! /bin/sh
b ()
{
x
}
i\
f true; then exec sed -f "$0" "$@"; fi
: ()
# sed script starts here
s/a/b/
説明:
b
。関数が構文的に整形式である限り、内容は重要ではありません(特に、空の関数を作成することはできません)。次に、true(常に)の場合sed
、スクリプトを実行します。()
ラベルへの分岐、そして整形式入力。次に、i
コマンドは常にスキップされるため、効果はありません。最後に、()
ラベルの後にスクリプトの有用な部分が続きます。#!/usr/bin/env
引数なし。」あまりうまく言い表されていません。おそらく「または#!/usr/bin/env sed
sedに対する議論はありません」。
GNU coreutils v8.30以降、次のことができます。
#!/usr/bin/env -S sed -f
この機能は、最近(2018年4月20日)に添加し、コミットにenv.c
追加GNU coreutilsのパッケージ、中-S
または--split-string
オプションを選択します。
env
manページから:
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-string
GNUの特徴であるenv
、具体的。
この回答は、エレガントなソリューションへのパスを提供します: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" "$@"
私はWalkerのソリューションが好きですが、改善することができます(コメントはフォーマット済みのテキストを受け入れないため、これを別の回答に入れる)。これは、LinuxまたはBashのすべてのバージョンで機能するわけではありませんが、Ubuntu 17.10では次のように削減できます。
#!/usr/bin/env bash
read SED_SCRIPT <<EOD
s/a/b/
EOD
sed "$SED_SCRIPT" "$@"
を削除しeval
てread
コマンドを簡略化できますが、ヒアドキュメント内のコメントを削除する必要があります。
また、sedについて知りたいと思っていたが、尋ねるのが怖かったすべてのために、http: //www.grymoire.com/unix/sed.htmlに非常に有用なチュートリアルがあります。これは、/usr/bin/env
sedへのパスを失い、ハードコーディングすることを犠牲にして、さらに優れたソリューションを示唆しています。
#!/bin/sed -f
s/a/b/
s/c/d/
これには、複数のs///
置換をサポートするという追加の利点があります。