У заголовку сценарію Bash, яка різниця між цими двома твердженнями:
#!/usr/bin/env bash#!/usr/bin/bash
Коли я переглянув env сторінку чоловіка , я отримав таке визначення:
env - run a program in a modified environment
Що це означає?
У заголовку сценарію Bash, яка різниця між цими двома твердженнями:
#!/usr/bin/env bash
#!/usr/bin/bash
Коли я переглянув env сторінку чоловіка , я отримав таке визначення:
env - run a program in a modified environment
Що це означає?
Відповіді:
Виконання команди наскрізний /usr/bin/envмає перевагу шукає то , що за замовчуванням версія програми знаходиться в поточному окр ironment.
Таким чином, вам не потрібно шукати його в певному місці в системі, оскільки ці шляхи можуть знаходитися в різних місцях в різних системах. Поки він на вашому шляху, він знайде його.
Недоліком є те, що ви не зможете пропустити більше одного аргументу (наприклад, ви не зможете написати /usr/bin/env awk -f), якщо ви хочете підтримати Linux, оскільки POSIX неясний щодо того, як слід інтерпретувати рядок, а Linux інтерпретує все після першого простір для позначення одного аргументу. Ви можете використовувати /usr/bin/env -Sдля деяких версій, envщоб обійти це, але тоді сценарій стане ще менш портативним і зламається на досить недавніх системах (наприклад, навіть Ubuntu 16.04, якщо не пізніше).
Ще один недолік полягає в тому, що оскільки ви не викликаєте явного виконуваного файлу, він має потенціал помилок, а також у проблемах із безпекою багатокористувацьких систем (якщо комусь вдалося отримати їх виконувану програму, наприклад, bashна вашому шляху).
#!/usr/bin/env bash #lends you some flexibility on different systems
#!/usr/bin/bash #gives you explicit control on a given system of what executable is called
У деяких ситуаціях може бути кращим перший (як, наприклад, запуск сценаріїв python з декількома версіями python, без необхідності переробляти виконуваний рядок). Але в ситуаціях, коли в центрі уваги є безпека, остання буде кращою, оскільки вона обмежує можливості введення коду.
#!/usr/bin/env echo Helloскаржиться: /usr/bin/env: echo Hello: No such file or directory. Мабуть, це трактується echo Helloяк єдиний аргумент /usr/bin/env.
envКоманда, безумовно, дозволяє передавати аргументи команді. Питання полягає в семантиці #!рядка, і це залежить від ядра. Останні ядра Linux дозволяють робити такі речі #!/usr/bin/env command args, але старіші ядра Linux та інші системи цього не дозволяють .
Використання #!/usr/bin/env NAMEзмушує пошук оболонки для першої відповідності NAME у змінній середовища $ PATH. Це може бути корисно, якщо ви не знаєте абсолютного шляху або не хочете його шукати.
Замість того, щоб чітко визначити шлях до інтерпретатора як в /usr/bin/bash/, використовуючи команду env, інтерпретатор шукається та запускається з того місця, де вперше його знайдено. Це має як плюси, так і недоліки
Якщо сценарії оболонки починаються з #!/bin/bash, вони завжди будуть працювати з bashз /bin. Якщо вони однак почати з #!/usr/bin/env bash, вони будуть шукати bashв $PATHі потім почати з першими вони можуть знайти.
Чому це було б корисно? Припустимо, ви хочете запускати bashсценарії, для яких потрібен bash 4.x або новіший, але у вашій системі встановлено лише bash3.x, і в даний час ваш дистрибутив не пропонує більш нової версії або ви не адміністратор і не можете змінити те, що встановлено в цій системі .
Звичайно, ви можете завантажити вихідний код bash і створити власний bash з нуля, розмістивши його, ~/binнаприклад. Ви також можете змінити $PATHзмінну у своєму .bash_profileфайлі, щоб вона була включена ~/binяк перший запис ( PATH=$HOME/bin:$PATHоскільки ~не буде розширюватися в $PATH). Якщо ви зараз зателефонуєте bash, оболонка спочатку шукатиме її $PATHв порядку, тому вона починається з того ~/bin, де вона знайде вашу bash. Те ж саме відбувається, якщо сценарії шукають для bashвикористання #!/usr/bin/env bash, тож тепер ці сценарії працюватимуть у вашій системі за допомогою власної bashзбірки.
Недоліком є те, що це може призвести до несподіваної поведінки, наприклад, один і той же сценарій на одній машині може працювати з різними інтерпретаторами для різних середовищ або користувачів з різними шляхами пошуку, викликаючи різного роду головні болі.
Найбільшим недоліком envє те, що деякі системи дозволять лише один аргумент, тому ви не можете цього зробити #!/usr/bin/env <interpreter> <arg>, оскільки системи будуть розглядатись <interpreter> <arg>як один аргумент (вони будуть трактувати це так, як якщо б вираз був цитований), і таким чином envбуде шукати інтерпретатора з ім'ям <interpreter> <arg>. Зауважте, що це не проблема самої envкоманди, яка завжди дозволяла проходити декілька параметрів, але із сизанг-аналізатором системи, що аналізує цей рядок ще до виклику env. Тим часом це було виправлено у більшості систем, але якщо ваш сценарій хоче бути надто портативним, ви не можете розраховувати, що це було виправлено у системі, яку ви будете працювати.
Це навіть може мати наслідки для безпеки, наприклад, якщо sudoвін не був налаштований на очищення навколишнього середовища або $PATHбув виключений з очищення. Дозвольте мені продемонструвати це:
Зазвичай /binце добре захищене місце, тільки rootтам вдається щось змінити. Ваш домашній каталог не є, проте жодна програма, яку ви запускаєте, не може внести зміни до нього. Це означає, що зловмисний код може помістити підробку bashв якийсь прихований каталог, змінити ваш, .bash_profileщоб включити цей каталог у свій $PATH, так що всі використовувані сценарії #!/usr/bin/env bashв кінцевому підсумку працюватимуть з цією підробкою bash. Якщо sudoтриває $PATH, ви у великій неприємності.
Наприклад, інструмент створює файл ~/.evil/bashіз таким вмістом:
#!/bin/bash
if [ $EUID -eq 0 ]; then
echo "All your base are belong to us..."
# We are root - do whatever you want to do
fi
/bin/bash "$@"
Зробимо простий сценарій sample.sh:
#!/usr/bin/env bash
echo "Hello World"
Доказ концепції (у системі, де sudoзберігається $PATH):
$ ./sample.sh
Hello World
$ sudo ./sample.sh
Hello World
$ export PATH="$HOME/.evil:$PATH"
$ ./sample.sh
Hello World
$ sudo ./sample.sh
All your base are belong to us...
Hello World
Зазвичай класичні оболонки повинні розташовуватися всередині, /binі якщо ви не хочете розміщувати їх там з будь-якої причини, насправді не проблема розміщувати симпосилання в таких /binточках, що вказують на їхні реальні місця (або, можливо, /binсаме це є посилання), Я б завжди ходив з #!/bin/shі #!/bin/bash. Просто занадто багато цього може зламатися, якщо вони більше не працюватимуть. Справа не в тому, що POSIX вимагає цієї позиції (POSIX не стандартизує імена шляхів і, отже, навіть не стандартизує функцію shebang), але вони настільки поширені, що навіть якщо система не запропонує /bin/sh, вона, ймовірно, все-таки зрозуміє #!/bin/shі знайте, що з ним робити, і це може бути лише для сумісності з існуючим кодом.
Але для більш сучасних, нестандартних, необов'язкових інтерпретаторів, таких як Perl, PHP, Python або Ruby, насправді не вказано ніде, де вони повинні бути розташовані. Вони можуть бути в , /usr/binале вони так само можуть бути в /usr/local/binабо в абсолютно іншій гілці ієрархії ( /opt/..., /Applications/...і т.д.). Ось чому вони часто використовують #!/usr/bin/env xxxсинтаксис shebang.
Я вважаю це корисним, бо коли я не знав про env, перед тим, як почати писати сценарій, я робив це:
type nodejs > scriptname.js #or any other environment
а потім я змінював цей рядок у файлі на shebang.
Я робив це, бо не завжди пам’ятав, де на моєму комп’ютері nodejs - / usr / bin / або / bin /, тому для мене envце дуже корисно. Можливо, з цим є деталі, але це моя причина