Яка різниця між ./ і sh для запуску сценарію?


71

Я написав простий сценарій. Коли я бігав sh <myscriptname.sh>, я отримав правильний вихід, але коли я запускався ./<myscriptname.sh>, я отримав помилку.

Яка різниця між тим, коли я shі ./?


15
Замість того, щоб просто сказати: "Я отримую помилку", це допоможе, якщо ви вставите те, що сказала помилка.
SpashHit

Відповіді:


67

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

З іншого боку, якщо ви запускаєте сам скрипт, система викликає вказану програму інтерпретатора та подає вміст скриптів. У цьому випадку процес виглядає як "filename.sh" без аргументів.

Ви повинні переконатися, що у вас є лінія вибуху:

#!/bin/bash
# bash script here

Рядок вибуху - це найперший рядок у скрипті і починається з тих самих двох символів #!, це те, що система читає, коли намагається виконати сценарій, а потім система передає сценарій програмі відразу після. Зауважте, що цей рядок не має нічого спільного з bash і працює так само добре, як для python та perl, хоча вони дуже різні мови. Ви б використали, #!/usr/bin/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. Але якщо сценарій запускається з правильними дозволами, тоді відображається назва сценарію.

Примітка. Якщо ви хочете поширити скрипт, доступний для всіх, то створіть довідкову сторінку та пакет дебюту, щоб встановити її. Нам потрібно зменшити кількість випадкових сценаріїв в Інтернеті та збільшити кількість деб, які можна видалити.


1
Ви також можете використовувати особисту папку бін: створіть папку бін для виходу з домашньої папки та увійдіть назад, і тоді ви зможете запускати будь-які сценарії в цій папці без sh або ./.
papukaija

Звичайно, але додавання домашньої папки до вашої PATH може бачити, як трохи болить. Краще встановіть речі. Хоча йшлося про те, щоб додати ~ / .local / bin до шляху за замовчуванням, щоб дозволити місцевим користувачам встановлювати пакунки.
Мартін Оуенс -доктормо-

Зауважте, що перекладачем за замовчуванням є bash, ні sh.
Натан Осман

1
Не ставте розширення до сценаріїв, особливо не тоді, коли ви його вставляєте PATH.
geirha

1
/usr/local/binце, мабуть, краще /usr/sbin- це вказує, що програма локальна для цієї машини, а не є частиною дистрибуції.
glenn jackman

41

Коротка версія:

  • sh- інтерпретатор командного рядка (тире).
    Запуск sh my_scriptзмушує тире інтерпретувати сценарій.

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


7
Це насправді ./нічого не знаходить, це метод виконання системи, який розглядає перші два байти файлу.
Мартін Оуенс -доктормо-

9
Абсолютно. Ось дуже довге пояснення всього цього. Я прагматичний :)
Стефано Палацо

Коли ви використовуєте, shа файл містить ша-баг, чи означає це, що ша-баг буде ігнорований чи він відкриє оболонку, де також shпосилання, а потім, можливо, якусь іншу оболонку чи що вона робить :)?
Іні

5

Різниця, яку ви робите,

  • з sh, ви запускаєте програму, яка інтерпретуватиме рядки у вашому сценарії так само, як ви б їх ввели в інтерактивний запит терміналу,

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


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>.


0

І відповідь, що sh - назва дуже популярної оболонки. Але застарілі і замінені іншими. У наш час sh пов'язаний з іншими снарядами, встановленими на машині. наприклад, я там поклав баш. Запуск будь-якої оболонки від sh зазвичай викликає деякий режим "сумісності" з оригінальною поведінкою "оболонки".

Тож рішення досить просте. Подивіться, що стоїть за командою sh (ls -al / bin / sh), і введіть #! / Bin / what_you_find_there як перший рядок (або якщо у вашому сценарії щось таке відредагуйте).

І в якості альтернативи може бути якась помилка в самому скрипті. Як і залежність, яку задовольняє sh, але не перекладач, який фактично використовується.


0
mkdir ~/bin ; cp myscript.sh ~/bin/

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

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


У Ubuntu за замовчуванням ~/.profileвже є код для додавання ~/bin, якщо він існує, до PATH. З іншого боку, не ставте розширення на сценарії.
geirha

1
Я посилався на <myscriptname.sh>, але що обґрунтовує не розміщувати розширення на сценарії? Зазвичай я це роблю, оскільки видимі прості текстові файли не дозволяють редагувати бінарні файли, які я також зберігаю в ~ / bin /. ( ls ~/bin/|wc -l = 428) Я поклав туди багато речі;)
Joey1978,

Уявіть, що ви пишете сценарій для досягнення конкретного завдання. Тоді ви зрозумієте, що написання цього конкретного сценарію в python зробить його набагато ефективнішим, тому ви перезаписуєте його в python. Тепер у вас є два варіанти. 1) Залиште зараз дуже оманливе розширення .sh-розширення або 2) перейменуйте скрипт і знайдіть і замініть усі способи використання сценарію, щоб використовувати нове ім'я. Якщо ви подивитеся на сценарії в /binі /usr/binпобачите, що вони не використовують розширення.
geirha
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.