Не можна, переносно, розміщувати більше одного аргументу на #!рядку . Це означає лише повний шлях і один аргумент (наприклад, #!/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 вимогливий щодо частин, які він пропускає.)