Написання скриптів оболонок, які працюватимуть на будь-якій оболонці (використовуючи кілька рядків shebang?)


19

Я щойно почав заглиблюватися в сценарій оболонки, і завжди просто кидав свій скрипт у файл, відзначав його, chmod +xа потім робив /path/to/script.shі нехай будь-який інтерпретатор за замовчуванням має свій шлях до нього, що я вважав, що це zsh, тому що це Я використовував для своєї оболонки. Мабуть, здається, що це просто /bin/shза замовчуванням, навіть якщо я виконую скрипт із запиту zsh, тому що я почав вводити специфічні для zsh речі в мої сценарії, і він не працює, якщо не запустити zsh /path/to/script.sh.

Щоб перейти до справи, ось мої запитання:

  1. Яка оболонка виконує сценарії, коли на початку немає рядка shebang ( #!/path/to/shell)? Я припускаю, /bin/shале не можу підтвердити.
  2. Що вважається "найкращою практикою" щодо написання скриптів оболонок, які працюватимуть на будь-якій платформі? (гаразд, це щось із відкритих)
  3. Чи можливо написати сценарій, який намагається використовувати zsh і повертається назад до bash, якщо zsh недоступний? Я спробував поставити дві лінії shebang, як нижче, але це просто помилки bad interpreter: /bin/zsh: no such file or directory, якщо я спробую це на машині без zsh.

    #!/bin/zsh

    #!/bin/bash

Відповіді:


26

Яка оболонка виконує сценарії, коли на початку немає рядка shebang (#! / Path / to / shell)? Я припускаю / bin / sh, але не можу підтвердити.

Ядро відмовляється виконувати такі сценарії і повертає ENOEXEC, тому точна поведінка залежить від програми запуску такого сценарію з .

  • bash 4.2.39 - використовує себе
  • busybox-ash 1.20.2 - використовує себе
  • тире 0,5,7 - пробіг / бін / ш
  • 1.23.1 риба - скаржиться на ENOEXEC, потім звинувачує неправильний файл
  • AT&T ksh 93u + 2012.08.01 - використовує себе
  • mksh R40f - працює / бін / ш
  • pdksh 5.2.14 - пробіг / бін / ш
  • sh-heirloom 050706 - використовує себе
  • tcsh 6.18.01 - пробіг / бін / ш
  • zsh 5.0.0 - працює / бін / ш
  • cmd.exe 5.1.2600 - виглядає на вас смішно.

У glibc функціонує execv()або execve()просто повертає ENOEXEC. Але execvp()приховує цей код помилки і автоматично викликає / bin / sh. (Це зафіксовано у виконанні (3p) .)

Що вважається "найкращою практикою" щодо написання скриптів оболонок, які працюватимуть на будь-якій платформі? (гаразд, це щось із відкритих)

Або дотримуйтесь shлише функцій, визначених POSIX, або просто пройдіть повний баш (який широко доступний) і згадайте про це у своїх вимогах, якщо розповсюджуєте його.

(Тепер, коли я думаю про це, Perl - чи, можливо, Python - був би ще більш портативним, не кажучи вже про кращий синтаксис.)

Завжди додайте рядок shebang. Якщо ви використовуєте bash або zsh, використовуйте #!/usr/bin/env bashзамість жорсткого кодування шлях оболонки. (Однак оболонка POSIX гарантовано є /bin/sh, тому пропустіть envу цьому випадку.)

(На жаль, навіть /bin/shце не завжди однаково. Програма autoconf GNU має мати справу з багатьма різними химерностями .)

Чи можливо написати сценарій, який намагається використовувати zsh і повертається назад до bash, якщо zsh недоступний? Я намагався поставити два рядки shebang, як нижче, але це просто помилки з поганим інтерпретатором: / bin / zsh: немає такого файлу чи каталогу , якщо я спробую його на машині без zsh.

Може бути лише одна лінія шебанга; все після символу нового рядка навіть не читається ядром, а трактується як коментар оболонок.

Це можна написати скрипт , який працює , як #!/bin/sh, перевірки яких оболонка є, і працює exec zsh "$0" "$@"або в exec bash "$0" "$@"залежності від результату. Однак синтаксис, що використовується bash та zsh, настільки різний у різних місцях, що я б не рекомендував робити це для вашого власного розуму.


1
як ви простежили, що насправді викликала кожна оболонка, коли вона отримала ENOEXEC?
swrobel

2
@SWrobel: Використання strace -f -e fork,clone,execve. Деякі снаряди продовжували виконуватись /bin/shпісля відмови; інші інтерпретували сценарій самі.
grawity

1
@SWrobel: Ще одним методом є запуск сценарію, який складається з readlink /proc/$$/exe.
grawity


1
Для cshі tcshповедінка залежить від того, починається сценарій #(у такому випадку вони посилаються на себе замість sh для інтерпретації сценарію). Це сходить до того часу, коли csh підтримував коментарі, але не оболонку Bourne, тому #був натяком на те, що це скрипт csh.
sch

2

1) Поточна оболонка, в якій ви працюєте. (Незалежно від оболонки)

2) Дотримуйтесь того ж типу оболонки (bash / dash / ash / csh / незалежно від вашого смаку) і переконайтеся, що на "підтримуваних платформах" встановлено оболонку, яку ви хочете використовувати за замовчуванням. Також спробуйте використовувати загальнодоступні команди в системах. Уникайте специфічних для машини варіантів.

3) Не існує насправді логіки "якщо-то-інше" interpreter directive. Ви повинні вказати оболонку, яка повинна існувати у всіх системах, які ви хочете підтримувати ... тобто #!/bin/bashабо вказати загальну #!/bin/sh, якщо ваш сценарій є досить загальним для всіх оболонок.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.