Тот же сценарий, открытый тремя разными способами, дает три разных результата. Зачем? [Дубликат]

7

У меня есть образец сценария (кредит идет kos ):

#!/bin/bash
cat <(cat /etc/lsb-release)

Я сохраняю этот скрипт как somename.sh в моем домашнем каталоге.

Теперь я пытаюсь открыть этот файл тремя способами:

sh somename.sh

bash somename.sh

./somename.sh

Итак, у меня есть два вопроса:

  1. Почему выходы для указанных выше команд отличаются, хотя они работают с одним и тем же сценарием?

    • sh создает ошибку синтаксиса

    • bash выводит желаемый результат

    • ./ дает ошибку с разрешением отказа

  2. Почему необходимо предоставить разрешение на выполнение скрипта только при запуске скрипта с использованием ./ и не обязательно в других случаях?

Спасибо заранее!

EDIT . Первая часть может быть похожа на дубликат , связанный с ней, но у меня было второй вопрос тоже.

    
задан Raphael 26.12.2015 в 11:19
источник

3 ответа

8

Как мы обсуждали в чате:

  1. sh script выдает ошибку, потому что вызов интерпретатора напрямую (в этом случае sh ) игнорирует shebang, а скрипт запускается в sh ; sh не поддерживает подстановки процессов ( <([...]) ), которые являются Bash-isms, поэтому скрипт выходит из строя.

    bash script не создает ошибку, потому что, несмотря на игнорирование shebang, скрипт все еще запущен в Bash, который поддерживает подстановки процесса.

    ./script выдает ошибку, потому что script не является исполняемым.

  2. Для запуска скрипта с ./ вы должны иметь бит выполнения для вашего пользователя, установленный в скрипте, это ограничение ОС.

    Итак, на самом деле вопрос: почему bash script не требует наличия бита выполнения, установленного для вашего пользователя, на script ?

    Это происходит потому, что при запуске bash script скрипт считывается Bash, а Bash имеет бит выполнения, установленный для вашего пользователя.

    Это означает, что Bash, имеющий разрешение на выполнение кода, может «обойти» ограничение OS на этом скрипте, и все потребности скрипта должны быть прочитаны Bash.

ответ дан kos 26.12.2015 в 11:59
источник
5
  • sh является символической ссылкой на оболочку dash и выдает синтаксическую ошибку, потому что в <( . . .) нет синтаксиса sh . Это только в bash (и в zsh и ksh , если я правильно помню).

  • bash выводит желаемый результат, потому что он находится в правильном синтаксисе bash, ничего неправильного там

  • ./ выдает ошибку с разрешением отказа, потому что вы в основном говорите: «Эй, оболочка, посмотрите на разрешения этого файла и посмотрите на первую строку (тот, у кого #!/bin/bash ) в моем текущем каталоге и выясните, как запустить этот скрипт для меня ». (обратите внимание: если бы у вас был скрипт в месте, включенном в вашу переменную $PATH , тогда вы просто запустили myScriptName.sh , и это все, но идея будет такой же, нам нужно проверить права администратора и какой интерпретатор для использования)

Перед запуском bash и dash и попросите их прочитать команды из файла. bash и dash исполняются на этот раз, а не скрипт. Скрипт теперь является источником команд, параметр. Разрешения на чтение всегда установлены для всех пользователей, поэтому оболочки будут читать его.

    
ответ дан Sergiy Kolodyazhnyy 26.12.2015 в 12:06
3

В общем случае sh , ash , dash , bash , csh , tcsh , zsh ... - это все оболочки с их собственными синтаксисами и характеристиками. Существуют некоторые совместимости, но они ориентированы [ 1 ] : оболочка bash выполнит скрипт sh , но не указан viceversa . Для вызова sh требуется меньше ресурсов, чем bash . Для одного экземпляра это не проблема, для тысяч это должно быть.

Способы выполнения.
Чтобы выполнить файл как программу под Linux, и если это скрипт или скомпилированный, он должен быть установлен как execute bit [ 2 ] , и он должен быть включен в один из каталогов вашего $PATH .

Если это скрипт, он может быть передан как аргумент относительной оболочке ( sh , bash ... myfile.whatever ): если он передан в неправильную оболочку вы можете получить неверное поведение и , если вам повезет ошибка ; в этом случае он не должен быть исполняемым , потому что это похоже на то, что вы пишете строки, написанные внутри скрипта, непосредственно в новой оболочке , которую вы вызываете. Вместо этого вы можете использовать source myfile или . myfile , которые эквивалентны для записи строки за строкой в текущей оболочке содержимого сценария.

Местоположение
Если исполняемая программа не включена в ваш путь, вы должны указать, где ее можно найти.

  • В вашем случае ./ означает только текущий каталог вашей оболочки, а ~/myfile.whatever должен адресовать файл myfile.whatever в вашем домашнем каталоге ~/ .
  • Вы можете вызвать его из другого места, например, с помощью /home/$USER/dir/myfile.whatever .
  • Если этот файл находится внутри каталога, включенного в ваш путь, вы можете вызвать его с помощью простого myfile.whatever .

В случае, если более одного исполняемого файла используют одно и то же имя, указание полного пути будет уверенным, какой из них вы собираетесь выполнить. which mycommand может сказать вам, какой из них будет выполнен (функция, псевдоним, встроенный или первый найденный на вашем пути), но он не может сказать, какой из них будет выполнен в будущем или у другого пользователя , Если вы прямо напишите полный путь, вы устраните эту двусмысленность. Полезно выполнять определенную версию программы, когда они устанавливаются больше одного в одно и то же время ... и во избежание троянов. В скрипте всегда рекомендуется писать /bin/bash вместо bash .     

ответ дан Hastur 26.12.2015 в 12:56