Посмотрите на код:
#!/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 всем этим исполняемым файлам.
Теперь не могли бы вы объяснить различия между всеми этими?
Единственное существенное различие между определением источника и выполнением сценария. source foo.sh
получит его и все другие примеры, которые Вы показываете, выполняются. Более подробно:
./file.sh
Это выполнит названный сценарий file.sh
это находится в текущем каталоге (./
). Обычно, когда Вы работаете command
, оболочка просмотрит каталоги в Вашем $PATH
для названного исполняемого файла command
. Если Вы даете полный путь, такой как /usr/bin/command
или ./command
, затем $PATH
проигнорирован и что определенный файл выполняется.
../file.sh
Это - в основном то же как ./file.sh
за исключением того, что вместо того, чтобы смотреть в текущем каталоге для file.sh
, это смотрит в родительском каталоге (../
).
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
переопределит строку хижины (если есть) и запустит скрипт с любой оболочкой, которую Вы говорите этому.
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"
И выполненный это различными способами только с единственным открытым терминалом:
Прямой запуск, ./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
показывает его вывод.
Прямой запуск с явным (удар) оболочка
$ bash foo.sh
The number of shells opened by terdon is 3
Здесь, потому что Вы работаете с bash foo.sh
, вывод ps
покажет bash foo.sh
и считайтесь. Так, здесь у нас есть родительский процесс, bash
запущение скрипта и клонированной оболочки (работающий ps
) все показанные, потому что теперь ps
покажет каждому из них, потому что Ваша команда будет включать слово bash
.
Прямой запуск с другой оболочкой (sh
)
$ sh foo.sh
The number of shells opened by terdon is 1
Это отличается, потому что Вы запускаете скрипт с sh
и нет bash
. Поэтому единственное bash
экземпляр является родительской оболочкой, где Вы запустили свой сценарий. Все другие упомянутые выше оболочки выполняются sh
вместо этого.
Определение источника (любой .
или 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
.