В чем различия между выполнением сценариев оболочки с использованием & ldquo; file file.sh & rdquo ;, & ldquo; ./ file.sh & rdquo ;, & ldquo; sh file.sh & rdquo ;, & ldquo ;. ./file.sh&rdquo ;?

Посмотрите на код:

#!/bin/bash
read -p "Eneter 1 for UID and 2 for LOGNAME" choice
if [ $choice -eq 1 ]
then
        read -p "Enter UID:  " uid
        logname=`cat /etc/passwd | grep $uid | cut -f1 -d:`
else
        read -p "Enter Logname:  " logname
fi
not=`ps -au$logname | grep -c bash`
echo  "The number of terminals opened by $logname are $not"

Этот код используется для определения количества терминалов, открытых пользователем на одном и том же ПК. Теперь в систему вошли два пользователя, скажем, x и y. В данный момент я вошел в систему как y, и у пользователя x открыто 3 терминала. Если я выполню этот код в y, используя различные способы, как упомянуто выше, то получится:

$ ./file.sh
The number of terminals opened by x are 3

$ bash file.sh
The number of terminals opened by x are 5

$ sh file.sh
The number of terminals opened by x are 3

$ source file.sh
The number of terminals opened by x are 4

$ . ./file.sh
The number of terminals opened by x are 4

Примечание. Я передал 1 и uid 1000 всем этим исполняемым файлам.

Теперь не могли бы вы объяснить различия между всеми этими?

13
задан 9 February 2016 в 20:24

1 ответ

Единственное существенное различие между определением источника и выполнением сценария. source foo.sh получит его и все другие примеры, которые Вы показываете, выполняются. Более подробно:

  1. ./file.sh

    Это выполнит названный сценарий file.sh это находится в текущем каталоге (./). Обычно, когда Вы работаете command, оболочка просмотрит каталоги в Вашем $PATH для названного исполняемого файла command. Если Вы даете полный путь, такой как /usr/bin/command или ./command, затем $PATH проигнорирован и что определенный файл выполняется.

  2. ../file.sh

    Это - в основном то же как ./file.sh за исключением того, что вместо того, чтобы смотреть в текущем каталоге для file.sh, это смотрит в родительском каталоге (../).

  3. sh file.sh

    Этот эквивалент sh ./file.sh, как выше его запустит названный скрипт file.sh в текущем каталоге. Различие - то, что Вы явно выполняете его с sh оболочка. В системах Ubuntu, который является dash и нет bash. Обычно, сценарии имеют строку хижины, которая дает программу, они должны быть выполнены как. Вызов их с другим переопределяет это. Например:

    $ cat foo.sh
    #!/bin/bash  
    ## The above is the shebang line, it points to bash
    ps h -p $$ -o args='' | cut -f1 -d' '  ## This will print the name of the shell
    

    Тот сценарий просто распечатает название оболочки, используемой для выполнения его. Давайте посмотрим то, что это возвращает при вызове по-разному:

    $ bash foo.sh
    bash
    $ sh foo.sh 
    sh
    $ zsh foo.sh
    zsh
    

    Так, называя вызов сценария с shell script переопределит строку хижины (если есть) и запустит скрипт с любой оболочкой, которую Вы говорите этому.

  4. source file.sh или . file.sh

    Это называют, удивительно достаточно, получая сценарий. Ключевое слово source псевдоним к встроенной оболочке . команда. Это - способ выполнить сценарий в текущей оболочке. Обычно, когда сценарий выполняется, он выполняется в его собственной оболочке, которая отличается, чем текущий. Проиллюстрировать:

    $ cat foo.sh
    #!/bin/bash
    foo="Script"
    echo "Foo (script) is $foo"
    

    Теперь, если я установил переменную foo к чему-то еще в родительской оболочке и затем запущенный скрипт, сценарий распечатает другое значение foo (потому что это также установлено в рамках сценария), но значение foo в родительской оболочке будет неизменно:

    $ foo="Parent"
    $ bash foo.sh 
    Foo (script) is Script  ## This is the value from the script's shell
    $ echo "$foo"          
    Parent                  ## The value in the parent shell is unchanged
    

    Однако, если я получу сценарий вместо того, чтобы выполнить его, то это будет выполнено в той же оболочке так значение foo в родителе будет изменен:

    $ source ./foo.sh 
    Foo (script) is Script   ## The script's foo
    $ echo "$foo" 
    Script                   ## Because the script was sourced, 
                             ## the value in the parent shell has changed
    

    Так, определение источника используется в нескольких случаях, где Вы хотите, чтобы сценарий влиял на оболочку, Вы выполняете его от. Это обычно используется, чтобы определить переменные оболочки и иметь их в наличии после того, как сценарий закончится.


Со все, что в памяти, причина Вы получаете различные ответы, в первую очередь, что Ваш сценарий не делает то, что Вы думаете, что это делает. Это считает количество раз этим bash появляется в выводе ps. Это не количество открытых терминалов, это - количество выполнения оболочек (на самом деле, это даже не, что, но это - другое обсуждение). Для разъяснения я упростил сценарий немного до этого:

#!/bin/bash
logname=terdon
not=`ps -au$logname | grep -c bash`
echo  "The number of shells opened by $logname is $not"

И выполненный это различными способами только с единственным открытым терминалом:

  1. Прямой запуск, ./foo.sh.

    $ ./foo.sh
    The number of shells opened by terdon is 1
    

    Здесь, Вы используете строку хижины. Это означает, что сценарий выполняется непосредственно тем, что установлено там. Это влияет на способ, из которого сценарий показывают в выводе ps. Вместо того, чтобы быть перечисленным как bash foo.sh, это только покажут как foo.sh что означает что Ваш grep пропустит его. Существует на самом деле 3 выполнения экземпляров удара: родительский процесс, удар, запускающий скрипт и другой, который работает ps команда. Это в последний раз важно, запуская команду с заменой команды (`command` или $(command)) результаты в копии родительской запускаемой оболочки и это выполняет команду. Здесь, однако, ни один из них не показывают из-за пути который ps показывает его вывод.

  2. Прямой запуск с явным (удар) оболочка

    $ bash foo.sh 
    The number of shells opened by terdon is 3
    

    Здесь, потому что Вы работаете с bash foo.sh, вывод ps покажет bash foo.sh и считайтесь. Так, здесь у нас есть родительский процесс, bash запущение скрипта и клонированной оболочки (работающий ps) все показанные, потому что теперь ps покажет каждому из них, потому что Ваша команда будет включать слово bash.

  3. Прямой запуск с другой оболочкой (sh)

    $ sh foo.sh
    The number of shells opened by terdon is 1
    

    Это отличается, потому что Вы запускаете скрипт с sh и нет bash. Поэтому единственное bash экземпляр является родительской оболочкой, где Вы запустили свой сценарий. Все другие упомянутые выше оболочки выполняются sh вместо этого.

  4. Определение источника (любой . или source, то же самое)

    $ . ./foo.sh 
    The number of shells opened by terdon is 2
    

    Как я объяснил выше, получение сценария заставляет это работать в той же оболочке как родительский процесс. Однако отдельная подоболочка запускается для запуска ps команда и это приносят общее количество к два.


Как заключительное примечание, корректный способ считать рабочие процессы не состоит в том, чтобы проанализировать ps но использовать pgrep. Всех этих проблем избежали бы, выполняли Вас просто

pgrep -cu terdon bash

Так, рабочая версия Вашего сценария, который всегда печатает правильное число, (отметьте отсутствие замены команды):

#!/usr/bin/env bash
user="terdon"

printf "Open shells:"
pgrep -cu "$user" bash

Это возвратится 1 при определении источника и 2 (потому что новый удар будет запущен для запущения скрипта) для всех других способов запуститься. Это все еще возвратится 1 при запуске с sh так как дочерний процесс не bash.

20
ответ дан 9 February 2016 в 20:24

Другие вопросы по тегам:

Похожие вопросы: