Echa un vistazo al código:
#!/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"
Este código se usa para averiguar el número de terminales abiertos por un usuario en la misma PC. Ahora hay dos usuarios conectados, digamos x e y. Actualmente estoy conectado como y y hay 3 terminales abiertas en el usuario x. Si ejecuto este código en y usando diferentes formas como se mencionó anteriormente, los resultados son:
$ ./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
Nota: Pasé 1 y uid 1000 a todos estos ejecutables.
Ahora, ¿puedes explicar las diferencias entre todos estos?
command-line
bash
scripts
Ramana Reddy
fuente
fuente
Respuestas:
La única diferencia importante es entre el abastecimiento y la ejecución de un script.
source foo.sh
lo buscará y todos los demás ejemplos que muestres se están ejecutando. Con más detalle:./file.sh
Esto ejecutará un script llamado
file.sh
que está en el directorio actual (./
). Normalmente, cuando ejecutacommand
, el shell buscará en los directorios de su$PATH
archivo ejecutable llamadocommand
. Si proporciona una ruta completa, como/usr/bin/command
o./command
,$PATH
se ignora y se ejecuta ese archivo específico.../file.sh
Esto es básicamente lo mismo que,
./file.sh
excepto que en lugar de buscar en el directorio actualfile.sh
, está buscando en el directorio padre (../
).sh file.sh
Esto equivale a
sh ./file.sh
, como arriba, ejecutará el script llamadofile.sh
en el directorio actual. La diferencia es que lo está ejecutando explícitamente con elsh
shell. En los sistemas Ubuntu, eso esdash
y nobash
. Por lo general, los scripts tienen una línea shebang que le da al programa el que deben ejecutarse. Llamarlos con uno diferente anula eso. Por ejemplo:Ese script simplemente imprimirá el nombre del shell utilizado para ejecutarlo. Veamos qué devuelve cuando se llama de diferentes maneras:
Entonces, llamar a llamar a un script con
shell script
anulará la línea shebang (si está presente) y ejecutará el script con cualquier shell que le diga.source file.sh
o. file.sh
Esto se llama, sorprendentemente, el abastecimiento del guión. La palabra clave
source
es un alias para el.
comando incorporado de shell . Esta es una forma de ejecutar el script dentro del shell actual. Normalmente, cuando se ejecuta un script, se ejecuta en su propio shell, que es diferente del actual. Para ilustrar:Ahora, si configuro la variable
foo
en otra cosa en el shell principal y luego ejecuto el script, el script imprimirá un valor diferente defoo
(porque también se establece dentro del script) pero el valor defoo
en el shell principal no cambiará:Sin embargo, si obtengo el script en lugar de ejecutarlo, se ejecutará en el mismo shell, por lo que se cambiará el valor de
foo
en el padre:Por lo tanto, el abastecimiento se usa en los pocos casos en los que desea que un script afecte al shell desde el que lo está ejecutando. Normalmente se usa para definir variables de shell y tenerlas disponibles una vez que finaliza el script.
Con todo eso en mente, la razón por la que obtienes respuestas diferentes es, en primer lugar, que tu guión no hace lo que crees que hace. Cuenta el número de veces que
bash
aparece en la salida deps
. Este no es el número de terminales abiertos , es el número de shells en ejecución (de hecho, ni siquiera es eso, pero esa es otra discusión). Para aclarar, simplifiqué un poco su guión para esto:Y ejecútelo de varias maneras con solo un terminal abierto:
Lanzamiento directo,
./foo.sh
.Aquí, estás usando la línea shebang. Esto significa que el script se ejecuta directamente por lo que esté configurado allí. Esto afecta la forma en que se muestra el script en la salida de
ps
. En lugar de aparecer comobash foo.sh
, solo se mostrará como lofoo.sh
que significa quegrep
lo perderá. En realidad, se están ejecutando 3 instancias de bash: el proceso principal, el bash que ejecuta el script y otro que ejecuta elps
comando . Esto último es importante, el lanzamiento de un comando con sustitución de comando (`command`
o$(command)
) da como resultado una copia del shell principal que se inicia y que ejecuta el comando. Aquí, sin embargo, ninguno de estos se muestra debido a la forma en queps
muestra su salida.Lanzamiento directo con shell explícito (bash)
Aquí, porque está ejecutando con
bash foo.sh
, la salida deps
se mostrarábash foo.sh
y se contará. Entonces, aquí tenemos el proceso padre, labash
ejecución del script y el shell clonado (ejecutandops
), todos mostrados porque ahoraps
mostrará cada uno de ellos porque su comando incluirá la palabrabash
.Lanzamiento directo con un shell diferente (
sh
)Esto es diferente porque está ejecutando el script con
sh
y nobash
. Por lo tanto, la únicabash
instancia es el shell principal donde inició su script. Todos los otros depósitos mencionados anteriormente están siendo ejecutados en sush
lugar.Abastecimiento (ya sea por
.
osource
, lo mismo)Como expliqué anteriormente, el abastecimiento de un script hace que se ejecute en el mismo shell que el proceso padre. Sin embargo, se inicia una subshell separada para iniciar el
ps
comando y eso lleva el total a dos.Como nota final, la forma correcta de contar los procesos en ejecución no es analizar
ps
sino usarpgrep
. Todos estos problemas se habrían evitado si hubieras corridoEntonces, una versión funcional de su script que siempre imprime el número correcto es (tenga en cuenta la ausencia de sustitución de comandos):
Eso devolverá 1 cuando se obtenga y 2 (porque se lanzará un nuevo bash para ejecutar el script) para todas las otras formas de lanzamiento. Todavía devolverá 1 cuando se inicie,
sh
ya que el proceso secundario no lo esbash
.fuente
./foo.sh
se ejecuta en un nuevo shell que no es una copia del padre. Por ejemplo, si configurafoo="bar"
en su terminal y luego ejecuta un script que se ejecutaecho $foo
, obtendrá una línea vacía ya que el shell del script no habrá heredado el valor de la variable.pgrep
es un binario separado, y sí, lo ejecuta el script que está ejecutando.