Чому цей скрипт працює в терміналі, але не з файлу?


19

У мене цей скрипт оболонки збережений у файлі: він робить деяку основну підстановку рядків.

#!/bin/sh
html_file=$1
echo "html_file = $html_file"
substr=.pdf
pdf_file="${html_file/.html/.pdf}"
echo "pdf_file = $pdf_file"

Якщо я вставити його в командний рядок, він буде добре:

$ html_file="/home/max/for_pauld/test_no_base64.html"
  echo "html_file = $html_file"
  substr=.pdf
  pdf_file="${html_file/.html/.pdf}"
  echo "pdf_file = $pdf_file"

дає

html_file = /home/max/for_pauld/test_no_base64.html
pdf_file = /home/max/for_pauld/test_no_base64.pdf

Ось вихід із луни вище - він працює за призначенням.

Але, коли я називаю сценарій, с

$ saucer "/home/max/for_pauld/test_no_base64.html"

Я отримую цей вихід:

html_file = /home/max/for_pauld/test_no_base64.html
/home/max/bin/saucer: 5: /home/max/bin/saucer: Bad substitution

Чи мій сценарій використовує іншу версію bash чи щось таке? Чи потрібно міняти лінійку shebang?


6
Це розширення параметрів - це башизм (ну, не-POSIX): змініть свій шебанг.
Jasonwryan

Спасибі! Це спрацювало. Я думаю, що я трохи туманний щодо різниці між shі bash. Я прочитаю на ньому. Якщо ви можете потрудитися зробити ваш коментар у відповідь, то я відзначу це правильним.
Макс Вільямс

Дав галочку герцогу за його детальну відповідь, але все одно дякую.
Макс Вільямс

2
@MaxWilliams: у двох словах, ш - оригінальна оболонка бурна. Усі сумісні сценарії повинні бути написані для sh. Але багато наступних оболонок (наприклад: bash, Bourne Again shell) "майже сумісні" і додають багато додаткової приємності. Такі як заміна, яку ви використовували. Сьогодні ви досить безпечні, використовуючи лише функції posix, але пам’ятайте, що портативність залежить навіть від більш вузького набору (тобто, лише sh). Отже, загалом, використовуйте: #!/usr/bin/env bashяк ваш шебанг, і використовуйте послідовно визначені заміни за вашим бажанням, але із застереженнями щодо переносимості. І читайте: unix.stackexchange.com/a/48787/27616
Олів'є

Відповіді:


37

Що ш

sh(або Мова командної оболонки) - мова програмування, описана стандартом POSIX . Вона має безліч реалізацій ( ksh88, dash, ...). bashтакож можна вважати реалізацією sh(див. нижче).

Оскільки shспецифікація, а не реалізація /bin/sh- це симпосилання (або жорстке посилання) до фактичної реалізації в більшості систем POSIX.

Що таке баш

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

bashпідтримує --posixкомутатор, що робить його більш сумісним з POSIX. Він також намагається імітувати POSIX, якщо його викликають як sh.

ш = баш?

Тривалий час /bin/shвикористовується для вказівки /bin/bashна більшість систем GNU / Linux. В результаті цього майже стало безпечно ігнорувати різницю між ними. Але це почало змінюватися нещодавно.

Деякі популярні приклади систем /bin/sh, на які не вказується /bin/bash(а на деяких з яких /bin/bashможе навіть не існувати), є:

  1. Сучасні системи Debian і Ubuntu, які за замовчуванням посилаються shна посилання dash;
  2. Busybox , який зазвичай запускається під час завантаження системи Linux як частина initramfs. Він використовує реалізацію ashоболонки.
  3. BSD і взагалі будь-які нелінукс-системи. Використовує OpenBSD pdksh, нащадок оболонки Корна. FreeBSD shє нащадком оригінальної оболонки UNIX Bourne. Solaris має власну, shяка довгий час не відповідала POSIX; безкоштовна реалізація доступна від проекту Heirloom .

Як ви можете дізнатися, на що /bin/shвказує ваша система?

Ускладнення полягає в тому, що це /bin/shможе бути символічним або жорстким зв’язком. Якщо це символічне посилання, портативний спосіб вирішити це:

% file -h /bin/sh
/bin/sh: symbolic link to bash

Якщо це міцне посилання, спробуйте

% find -L /bin -samefile /bin/sh
/bin/sh
/bin/bash

Насправді -Lпрапор охоплює як посилання, так і жорсткі посилання, але недоліком цього методу є те, що він не є портативним - POSIX не потребує find підтримки -samefileопції, хоча і GNU find, і FreeBSD знаходять підтримку.

Лінія Шебанг

Зрештою, вирішувати, який саме використовувати, вирішувати, написавши рядок «shebang».

Напр

#!/bin/sh

буде використовувати sh(і що б там не сталося),

#!/bin/bash

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

#!/bin/dash

Який використовувати

Для власних сценаріїв я віддаю перевагу shз наступних причин:

  • вона стандартизована
  • набагато простіше і простіше вчитись
  • він портативний у системах POSIX - навіть якщо вони трапляються bash, їх не потрібно матиsh

Є і переваги використання bash. Його особливості роблять програмування більш зручним і схожим з програмуванням в інших сучасних мовах програмування. Сюди входять такі речі, як масштабовані локальні змінні та масиви. Plain sh- це дуже мінімалістична мова програмування.


Дякую за детальну відповідь: я використовую Linux Mint, який базується на Debian і /bin/shсправді є посиланням на /bin/dash.
Макс Вільямс

Якщо ви хочете дотримуватися POSIX sh, то краще повністю залишити шебанг: Якщо перший рядок файлу команд оболонки починається з символів "#!", Результати не визначені pubs.opengroup.org/onlinepubs/009695399/ комунальні послуги /…
Daniel Jour

4
@DanielJour Якщо будь-яка система, схожа на Unix, відмовилася від звичайної підтримки shebangs, вона зламає стільки речей, це було б практично непридатним. Тож це фактично стандарт, навіть якщо він не вказаний в POSIX. Єдине актуальне питання сумісності полягає в тому, що шлях до перекладачів може відрізнятися.
Бармар

23

Додаючи до чудової відповіді від @ Hunter.S.Thompson, я хотів би зазначити, що частина портативного сценарію - це не портативна

pdf_file="${html_file/.html/.pdf}"

Розширення ${variable/search/replace}GNU. Але ви можете легко уникнути цього за допомогою чистого POSIX:

pdf_file="${html_file%.html}".pdf

Слідом за Хантером, це краще виправлення, ніж зміна шебангу на #! /bin/bash


Дякую - я погоджуюся, що це "чистіший" виправлення, але я вважаю за краще завантажений шебангом баш, оскільки bash - це те, що я звичайно використовую в терміналі (за замовчуванням), і простіше, щоб сценарії виконували те саме, що і звичайні командний рядок.
Макс Вільямс

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