заголовки сценарію оболонки (#! / bin / sh проти #! / bin / csh)


92

Чому всі файли скриптів починаються з

#!/bin/sh

або с

#!/bin/csh

Це потрібно? Яка мета цього? І яка різниця між ними?


1
Для сценарію csh слід використовувати #!/bin/csh -f; -fговорить оболонці ні до джерела користувача .loginі .cshrc, що робить скрипт запущений швидше і уникнути залежностей від настройки користувача. (Або ще краще, не пишіть скрипти csh.) Не використовуйте -fдля скриптів sh або bash; воно не має однакового значення.
Кіт Томпсон,

Відповіді:


99

Це відомо як Shebang:

http://en.wikipedia.org/wiki/Shebang_(Unix)

#! інтерпретатор [необов’язково-аргумент]

Шебанг актуальний лише тоді, коли сценарій має дозвіл на виконання (наприклад, chmod u + x script.sh).

Коли оболонка виконує сценарій, вона використовуватиме вказаний інтерпретатор.

Приклад:

#!/bin/bash
# file: foo.sh
echo 1

$ chmod u+x foo.sh
$ ./foo.sh
  1

@Kolob Canyon вам не потрібно, але це може допомогти деяким редакторам із підсвічуванням синтаксису (хоча зазвичай є й інші способи досягнення того самого): unix.stackexchange.com/a/88730/193985
Снайдер,

42

#!Рядок повідомляє ядро ( в Зокрема, про здійсненні execveсистемного виклику) , що ця програма написана на інтерпретованих мовах; абсолютна назва шляху, що слідує, ідентифікує інтерпретатор. Програми, скомпільовані до машинного коду, починаються з іншої послідовності байтів - на більшості сучасних Unix, 7f 45 4c 46( ^?ELF), яка ідентифікує їх як такі.

Ви можете поставити абсолютний шлях до будь-якої програми, яку хочете після #!, якщо ця програма сама не є #!сценарієм. Ядро переписує виклик

./script arg1 arg2 arg3 ...

де ./scriptпочинається, скажімо, #! /usr/bin/perlтак, ніби командний рядок насправді був

/usr/bin/perl ./script arg1 arg2 arg3

Або, як ви вже бачили, ви можете використовувати #! /bin/shдля написання сценарію, призначеного для інтерпретації sh.

#!Рядок обробляється тільки , якщо ви безпосередньо викликати скрипт ( ./scriptв командному рядку); файл також повинен бути виконуваним ( chmod +x script). Якщо ви зробите sh ./scriptце, #!рядок не є необхідним (і буде проігноровано, якщо він присутній), і файл не повинен бути виконуваним. Точка в функції, щоб дозволити вам безпосередньо Invoke програми інтерпретовані мови , не знаючи , на якій мові вони написані. (Do grep '^#!' /usr/bin/*- ви виявите , що дуже багато фондових програми, насправді , використовуючи цю функцію.)

Ось деякі правила використання цієї функції:

  • Це #!повинні бути перші два байти у файлі. Зокрема, файл повинен мати ASCII-сумісне кодування (наприклад, UTF-8 буде працювати, але UTF-16 ні) і не повинен починатися з "позначки порядку байтів", або ядро ​​не розпізнає його як #!сценарій.
  • Шлях після #!повинен бути абсолютним шляхом (починається з /). Він не може містити пробілу, символів табуляції та символів нового рядка.
  • Це гарний стиль, але не обов’язковий, щоб поставити простір між #!і /. Не розміщуйте там більше одного місця.
  • Ви не можете розміщувати змінні оболонки на #!рядку, вони не будуть розширені.
  • Ви можете поставити один аргумент командного рядка після абсолютного шляху, відокремлений від нього одним пробілом. Як і абсолютний шлях, цей аргумент не може містити символи пробілу, табуляції або нового рядка. Іноді це потрібно для того, щоб щось запрацювало ( #! /usr/bin/awk -f), іноді це просто корисно ( #! /usr/bin/perl -Tw). На жаль, ви не можете поставити два або більше аргументів після абсолютного шляху.
  • Деякі люди скажуть вам використовувати #! /usr/bin/env interpreterзамість #! /absolute/path/to/interpreter. Це майже завжди помилка. Це робить поведінку вашої програми залежно від $PATHзмінної користувача, який викликає сценарій. І не всі системи мають envнасамперед.
  • Програми, які потребують setuidабо setgidпривілеї не можуть використовувати #!; їх потрібно скомпілювати до машинного коду. (Якщо ви не знаєте, що setuidє, не хвилюйтеся з цього приводу.)

Що стосується csh, це стосується shприблизно того, як замінник чаю Nutrimat Advanced Tea робить до чаю. Він має (чи, скоріше, мав; сучасні реалізації програми shназдогнали) низку переваг перед shінтерактивним використанням, але використання його (або його нащадка tcsh) для створення сценаріїв майже завжди є помилкою . Якщо ви загалом не знаєте сценаріїв оболонки, настійно рекомендую ігнорувати їх і зосередитись на цьому sh. Якщо ви використовуєте cshродича як оболонку для входу, перейдіть на bashабо zsh, щоб інтерактивна мова команд була такою ж, як мова сценаріїв, яку ви вивчаєте.


Останні версії Linux дозволяють вказаному інтерпретатору бути сценарієм. Поширеною практикою є пропускання пробілу після #!; немає коментарів щодо того, чи це хороший стиль. Дивіться це питання та мою відповідь для обговорення плюсів і мінусів #!/usr/bin/envхакерства.
Кіт Томпсон,

@KeithThompson У мене склалося враження, що Linux - це єдиний поширений варіант Unix, який дозволяє інтерпретатору бути сценарієм, тому на нього все ще не можна покладатися. Оскільки я писав це, я сам стикався з ситуацією, коли це #!/usr/bin/envбуло правильно, але я залишаюсь на мою думку, що це майже завжди погана ідея.
zwol

4

Це визначає, яку оболонку (інтерпретатор команд) ви використовуєте для інтерпретації / запуску вашого сценарію. Кожна оболонка дещо відрізняється за тим, як вона взаємодіє з користувачем і виконує сценарії (програми).

Коли ви вводите команду в рядку Unix, ви взаємодієте з оболонкою.

Наприклад, #!/bin/cshвідноситься до C-оболонки, /bin/tcsht-оболонки, /bin/bashоболонки bash тощо.

Ви можете сказати, яку інтерактивну оболонку ви використовуєте

 echo $SHELL

команди, або як варіант

 env | grep -i shell

Ви можете змінити свою командну оболонку за допомогою chshкоманди.

Кожен має дещо інший набір команд і спосіб призначення змінних, а також свій власний набір конструктивних програм. Наприклад, оператор if-else з bash виглядає інакше, ніж той, що міститься в оболонці C.

Ця сторінка може зацікавити, оскільки вона "перекладає" між командами / синтаксисом bash та tcsh.

Використання директиви у сценарії оболонки дозволяє запускати програми, використовуючи іншу оболонку. Наприклад, я використовую tcshоболонку інтерактивно, але часто запускаю скрипти bash, використовуючи / bin / bash у файлі сценарію.

Окрім:

Ця концепція поширюється і на інші сценарії. Наприклад, якщо ви програмуєте на Python, який ви б поставили

 #!/usr/bin/python

у верхній частині вашої програми Python


То чи потрібно? Як я знаю, яку оболонку я насправді використовую?
One Two Three

Отже, якщо я пишу сценарії для того, щоб хтось використовував їх на своїй машині, і я не знаю, яку оболонку вони використовують. (Ця людина, на жаль, не знає про це, тому все, що він може зробити, це запустити сценарій, не змінюючи нічого). Чи можу я зробити щось подібне #! $SHELL? Чи поставить це правильну оболонку в Shebang?
One Two Three

1
@OneTwoThree Більшість систем мають стандартні оболонки, якщо ви напишете скрипт bash або csh, ви будете в порядку. Яку оболонку вони використовують в інтерактивному режимі, не має значення, в чому полягає краса наприклад, !#/bin/bashдирективи. Він повідомляє системі, яку оболонку використовувати для виконання вашого сценарію оболонки.
Левон

Значення $SHELLнеобов’язково вказує вам, яку оболонку ви запускаєте на даний момент; це зазвичай повідомляє вам вашу оболонку за замовчуванням . tcsh набори $versionта $tcsh; баш-набори $BASH_VERSION. Не всі оболонки обов'язково мають схожі механізми.
Кіт Томпсон,

1
@OneTwoThree: #!рядок повинен відповідати синтаксису сценарію, а не інтерактивній оболонці, що використовується тим, хто запускає сценарій.
Кіт Томпсон,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.