В чем разница между ./ и sh для запуска скрипта?

71

Я написал простой сценарий. Когда я бегу sh <myscriptname.sh>, я получаю правильный вывод, но когда я бегу ./<myscriptname.sh>, я получаю ошибку.

Какая разница между тем, когда я делаю shи ./?

mr_eclair
источник
15
Вместо того, чтобы просто сказать «Я получаю ошибку», было бы полезно, если бы вы вставили в текст сообщения об ошибке.
SpashHit

Ответы:

67

Когда вы запускаете любой сценарий, передавая имя файла программе-интерпретатору сценария, вы запускаете программу-интерпретатор со сценарием в качестве аргумента, переданного ему. Например, это будет выглядеть как процесс 'sh' с аргументом 'filename.sh'. shИнтерпретатор открывает файл.

С другой стороны, если вы запускаете сам скрипт, система вызывает указанную программу интерпретатора и передает содержимое скриптов. В этом случае процесс выглядит как «filename.sh» без аргументов.

Вы должны убедиться, что у вас есть линия взрыва:

#!/bin/bash
# bash script here

Строка взрыва - это самая первая строка в скрипте, которая начинается с тех же двух символов #!, это то, что система читает, когда она пытается выполнить скрипт, а затем система сразу передает скрипт в программу. Обратите внимание, что эта строка не имеет ничего общего с bash и работает так же хорошо для python и perl, хотя они очень разные языки. Вы могли бы использовать, #!/usr/bin/pythonнапример, а затем следовать за ним с кодом Python.

Как только у вас есть ваш скрипт, убедитесь, что вы установили права на выполнение:

chmod a+x filename.sh

Затем вы можете запустить скрипт как собственный процесс:

./filename.sh

Или поместите файл в известное место с хорошим именем программы, как /usr/sbinи запустить из любого места:

sudo cp filename.sh /usr/sbin/program-name
program-name

И это действительно практическое преимущество использования линии взрыва с правильными разрешениями - все дело в развертывании . Пользователям очень сложно запустить скрипт, если они должны помнить, с какой программой запускать скрипт. Не забывайте указывать полный путь к скрипту каждый раз, когда они захотят его запустить. Где , как положить его в /usr/local/bin, например, и сделать его исполняемым, можно сэкономить очень много горя для людей , которые пытаются использовать ваш сценарий. Эти программы затем становятся доступными для всех пользователей на вашем компьютере.

Это также хорошо для идентификации. Если вы войдете в topпрограмму, сценарий, запускаемый без строки взрыва, будет иметь только имя интерпретатора, т. Е. bash, perlИли python. Но если скрипт запускается с нужными разрешениями, то отображается имя скрипта.

Примечание. Если вы хотите распространять сценарий, доступный для всех, создайте страницу руководства и пакет deb для его установки. Нам нужно уменьшить количество случайных скриптов в сети и увеличить количество дэбов, которые можно удалить.

Мартин Оуэнс -доктормо-
источник
1
Вы также можете использовать личную папку bin: создайте папку bin в своей домашней папке, выйдите из системы и снова войдите в систему, после чего вы сможете запускать любые сценарии в этой папке без sh или ./.
Папукайя
Конечно, но добавление вашей домашней папки в PATH может показаться головной болью. Лучше установить вещи. Хотя были некоторые разговоры о добавлении ~ / .local / bin к пути по умолчанию, чтобы позволить локальным пользователям устанавливать пакеты.
Мартин Оуэнс -доктормо-
Обратите внимание, что интерпретатор по умолчанию - bashнет sh.
Натан Осман
1
Не устанавливайте расширения в сценарии, особенно если вы их вставляете PATH.
Гейра
1
/usr/local/binВероятно, лучше /usr/sbin- это означает, что программа является локальной для этой машины, а не частью дистрибутива.
Гленн Джекман
41

Краткая версия:

  • shинтерпретатор командной строки (тире)
    Запуск sh my_scriptзаставляет dash интерпретировать скрипт.

  • ./пытается выяснить, какой интерпретатор использовать, посмотрев на первую строку. Например #!/bin/bash, или даже #!/bin/ruby(в отличие от бега ruby my_script).

Стефано Палаццо
источник
7
На самом деле это не то, ./что находит, это метод выполнения системы, который просматривает первые два байта файла.
Мартин Оуэнс -доктормо-
9
Абсолютно. Вот очень длинное объяснение всего этого. Я прагматичный :)
Стефано Палаццо
Когда вы используете shи файл содержит sha-bang, означает ли это, что sha-bang будет проигнорирован или откроет оболочку, в которой также есть shссылки, а затем, возможно, какую-нибудь другую оболочку или что она делает :)?
Ини
5

Разница в том, что

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

  • когда ./вы делаете ярлык, предполагая, что скрипт находится прямо здесь, в текущем каталоге, в котором вы сидите, и он будет исполняемым (потому что, например, вы его выпустили chmod +x myscript.sh), сохраняя ваше бесценное время на будущее :-)

meduz
источник
3
+1 за то, что единственный, кто кратко заявляет, что файл должен быть исполняемым.
Микель
2
Обратите внимание, что с shфайлом не обязательно должен быть исполняемый файл.
Ини
3

Есть три основные причины, по которым вы можете получить ошибку:

  • файл не является исполняемым
    бежать , chmod +x <myscriptname.sh>чтобы исправить
  • раздел не позволяет запускать скрипты (смонтирован " noexec")
    копировать скрипт в/usr/local/bin
  • #!линия ошибки
    убедитесь , что первая строка #!/bin/shили#!/bin/bash

Если ваша первая строка выглядит правильно, но все еще не работает, убедитесь, что в файле нет окончаний строки DOS.

Ошибка будет выглядеть примерно так:

$ ./myscript.sh
bash: ./myscript.sh: /bin/bash^M: bad interpreter: No such file or directory

Вы можете это исправить, выполнив dos2unix <myscriptname.sh>, или если у вас нет этого
perl -p -i -e 's/\r\n$/\n/' <myscriptname.sh>.

Mikel
источник
0

И ответ таков: sh - это имя очень популярной оболочки. Но устаревшие и заменены другими. В настоящее время sh связан с другими оболочками, установленными на машине. например, я поместил Баш там. Запуск любой оболочки из sh обычно вызывает некоторый режим «совместимости» с оригинальным поведением «оболочки».

Так что решение довольно простое. Посмотрите, что стоит за командой sh (ls -al / bin / sh), и поместите #! / Bin / what_you_find_there в качестве первой строки (или, если в вашем скрипте есть что-то подобное, отредактируйте ее).

И наоборот, в самом скрипте может быть какая-то ошибка. Как и зависимость, которую встречает sh, но не интерпретатор, который фактически используется.

przemo_li
источник
0
mkdir ~/bin ; cp myscript.sh ~/bin/

echo "export PATH="$PATH:/home/$USER/bin" >> ~/.profile ; source ~/.profile ; 

Не /usr/sbin, это для ненужных административных инструментов, /usr/local/binэто лучший выбор, если вы не хотите иметь ~/bin/, но sudoжелательно избегать как можно больше.

Joey1978
источник
В Ubuntu по умолчанию ~/.profileуже есть код для добавления ~/bin, если он существует, в PATH. С другой стороны, не помещайте расширения в сценарии.
Гейра
1
Я ссылался на <myscriptname.sh>, но в чем смысл не добавлять расширения в сценарии? Я обычно так делаю, потому что такие обычные текстовые файлы не позволяют мне редактировать двоичные файлы, которые я также храню в ~ / bin /. ( ls ~/bin/|wc -l = 428) Я положил много вещей там;)
Joey1978
Представьте, что вы пишете сценарий для достижения конкретной задачи. Затем вы понимаете, что написание этого конкретного скрипта на python сделает его намного более эффективным, поэтому вы переписываете его на python. Теперь у вас есть два варианта. 1) Оставьте теперь очень вводящее в заблуждение расширение .sh или 2) переименуйте скрипт и найдите и замените все варианты использования скрипта на новое имя. Если вы посмотрите на скрипты, /binи /usr/binвы увидите, что они не используют расширения.
Гейра