Не можна, переносно, розміщувати більше одного аргументу на #!
рядку . Це означає лише повний шлях і один аргумент (наприклад, #!/bin/sed -f
або #!/usr/bin/sed -f
), або #!/usr/bin/env
ніякий аргумент для перекладача.
Обхід для отримання портативного скрипту полягає у використанні #!/bin/sh
та оболонці оболонки, передаючи скрипт sed як аргумент командного рядка. Зауважте, що це не санкціонується POSIX (мультиінструкційні сценарії повинні писатися з окремим -e
аргументом для кожної інструкції щодо переносимості), але це працює з багатьма реалізаціями.
#!/bin/sh
exec sed '
s/a/b/
' "$@"
Для довгого сценарію може бути зручніше використовувати гередок. Перевагою гередока є те, що вам не потрібно цитувати єдині цитати всередині, якщо такі є. Основним недоліком є те, що сценарій подається на стандартний вхід з двома прикрими наслідками. Деякі версії 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
; вміст не має значення, поки функція синтаксично сформована (зокрема, ви не можете мати порожню функцію). Тоді, якщо це правда (тобто завжди), виконуйте sed
сценарій.
- Під sed: гілка на
()
етикетку, потім якийсь добре сформований ввід. Потім i
команда, яка не має ефекту, тому що вона завжди пропускається. Нарешті ()
мітка з наступною корисною частиною сценарію.
- Тестували під GNU sed, BusyBox та OpenBSD. (На GNU sed можна втекти чимось простішим, але OpenBSD sed вимогливий щодо частин, які він пропускає.)