Вы не можете, переносимым, поставить более одного аргумента в #!
строке . Это означает только полный путь и один аргумент (например, #!/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
; содержимое не имеет значения, пока функция синтаксически правильно сформирована (в частности, у вас не может быть пустой функции). Затем, если true (т.е. всегда), выполнить sed
на сценарии.
- Под sed: ответвление к
()
метке, затем некоторый правильно сформированный ввод. Затем i
команда, которая не имеет никакого эффекта, потому что она всегда пропускается. Наконец за ()
меткой следует полезная часть скрипта.
- Протестировано под GNU sed, BusyBox и OpenBSD. (В GNU sed вы можете избежать неприятностей, но OpenBSD sed требователен к тем частям, которые он пропускает.)