bash scripting
ls listar archivos
echo $SHELL
Esto me dice que tipo de shell estoy usando.
A script is esencially a text file with one or more commanda inside.
sudo chmod +x [Link]
ls -l muestra los permisos
Una vez con permisos podemos hacer
./[Link] en lugar de bash [Link]
Bash script:
ls
pwd
Lo que me enteré es que no hace falta poner bin bash arriba, mientras tenga los
😅
comandos válidos se ejecutará. Incluso no es necesario usar la extension .sh.
Lo escribes, lo guardas y lo marcas ejecutable y funciona.
Obviamente poner .sh es una practica habitual.
Esto es la shebang
Y dice que vamoa a usar bash como interprete
#!/bin/bash
echo "hello world!"
echo "My current working directory is:"
pwd
Variables
myname="Emm"
echo $myname
Salida:
Emm
Si hago echo $nueva_variable no muestra nada porque está vacía.
Siempre se usa $variable para referenciar las mismas.
Las variables en la consola no son persistentes. Por eso generalmente se escriben en el
script y siempre se cargaran a medida que se lee el script.
#!/bin/bash
myname="Emm"
myage="37"
echo "Hello, my name is $myname."
echo "I'm $myage years old."
Salida:
Hello, my name is Emm.
I'm 37 years old.
Las referencias dentro de las variables funcionan aun estando en un string con las
comillas puestas.
Si pongo comillas simples entonces no funcionará:
echo 'My name is $myname'
La salida será:
My name is $myname
Ctrl+k deletes entire line (cut)
Why we want to use variables.
Avoid retyping
Capture the output of a command
Para capturar la salida de un comando en una variable:
variable=$(comando)
ejemplo:
files=$(ls)
echo $files
y me imprime el contenido del ls.
El poner comandos entre parentesis es lo que se llama una subshell. Es decir ejecuta
comandos de shell en background y los asigna a una variable.
files=$(pwd)
echo $files
Salida:
/home/emm
Comando date
#!/bin/bash
now=$(date)
echo "The system time and date is: "
echo $now
Salida:
The system time and date is:
dom 06 oct 2024 20:10:48 -03
También podría hacerse sin usar la variable, por ejemplo:
#!/bin/bash
echo "The system time and date is: "
date
Salida:
The system time and date is:
dom 06 oct 2024 20:10:12 -03
Otro ejemplo:
#!/bin/bash
name="Emm"
now=$(date)
echo "Hello $name"
echo "The system time and date is $now"
echo $now
echo "Your username is $USER"
pero esperemos, nunca creamos una variable USER 🤔😂
Sin embargo hay una variable interna que esta declarada y que contiene el nombre del
usuario actual. Hay varias variables de entorno por defecto.
Para verlas puedes usar el comando env y hay un monton de variables de entorno
junto con sus valores ❤️❤️❤️
SHELL=/bin/bash
SESSION_MANAGER=local/camila:@/tmp/.ICE-unix/12841,unix/camila:/tmp/.ICE-
unix/12841
QT_ACCESSIBILITY=1
COLORTERM=truecolor
XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/etc/xdg
SSH_AGENT_LAUNCHER=gnome-keyring
XDG_MENU_PREFIX=gnome-
GNOME_DESKTOP_SESSION_ID=this-is-deprecated
LC_ADDRESS=es_AR.UTF-8
GNOME_SHELL_SESSION_MODE=ubuntu
LC_NAME=es_AR.UTF-8
SSH_AUTH_SOCK=/run/user/1000/keyring/ssh
XMODIFIERS=@im=ibus
DESKTOP_SESSION=ubuntu
LC_MONETARY=es_AR.UTF-8
GTK_MODULES=gail:atk-bridge
PWD=/home/emm
LOGNAME=emm
XDG_SESSION_DESKTOP=ubuntu
XDG_SESSION_TYPE=wayland
SYSTEMD_EXEC_PID=13093
XAUTHORITY=/run/user/1000/.mutter-Xwaylandauth.UE8QU2
HOME=/home/emm
USERNAME=emm
IM_CONFIG_PHASE=1
LC_PAPER=es_AR.UTF-8
LANG=en_US.UTF-8
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33
;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=3
4;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.t
az=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.tx
z=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;3
1:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*
.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rp
m=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=
01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;
31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;3
5:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;
35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;3
5:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35
:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.webp=01;3
5:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:
*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.
avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=
01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00
;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;
36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:
*.opus=00;36:*.spx=00;36:*.xspf=00;36:
XDG_CURRENT_DESKTOP=ubuntu:GNOME
VTE_VERSION=6800
WAYLAND_DISPLAY=wayland-0
GNOME_TERMINAL_SCREEN=/org/gnome/Terminal/screen/e22ea232_7e7a_4321_b3c2_d
043dd2e0841
GNOME_SETUP_DISPLAY=:1
LESSCLOSE=/usr/bin/lesspipe %s %s
XDG_SESSION_CLASS=user
TERM=xterm-256color
LC_IDENTIFICATION=es_AR.UTF-8
LESSOPEN=| /usr/bin/lesspipe %s
USER=emm
GNOME_TERMINAL_SERVICE=:1.979
DISPLAY=:0
SHLVL=1
LC_TELEPHONE=es_AR.UTF-8
QT_IM_MODULE=ibus
LC_MEASUREMENT=es_AR.UTF-8
XDG_RUNTIME_DIR=/run/user/1000
LC_TIME=es_AR.UTF-8
XDG_DATA_DIRS=/usr/share/ubuntu:/home/emm/.local/share/flatpak/exports/sha
re:/var/lib/flatpak/exports/share:/usr/local/share/:/usr/share/:/var/lib/s
napd/desktop
PATH=/home/emm/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bi
n:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin
GDMSESSION=ubuntu
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
LC_NUMERIC=es_AR.UTF-8
_=/usr/bin/env
lowercase names of variables is best practices.
Math Functions
Para hacer cálculos en bash a diferencia de python en el que simplemente haríamos:
30 + 10
en bash debemos dejarle claro al interprete que es lo que estamos queriendo hacer.
Vamoa a usar expr para indicar que queremos que evalúe una expresión.
expr 30 + 10
Salida:
40
expr 30 - 10
Salida:
20
expr 30 / 10
Salida:
expr 4 no funciona porque en bash es una wildcard, un comodín para indicar todos.
Como en *.txt
Asi que tenemos que "escapar" ese carácter:
expr 100 \* 4
Salida:
400
mynum1=100 No lo ponemos entde comillas porque son números, no strings.
echo $mynum1
Salida:
100
expr $mynum1 + 50
Salida:
150
mynum2=88
expr $mynum1 + $mynum2
Salida:
188
Statements
#!/bin/bash
mynum=200
if [ $mynum -eq 200 ]
then
echo "The condition is true."
fi
Salida:
The condition is true.
Esto generalmente no es tan util porque la mynum es un valor fijo pero si cambiara
entonces si tendría sentido.
-eq is for 'equal'.
if [ $mynum is equal to 200 ]
#!/bin/bash
mynum=300
if [ $mynum -eq 200 ]
then
echo "The condition is true."
else
echo "The variable does not equal 200. "
fi
Salida:
The variable does not equal 200.
#!/bin/bash
mynum=300
if [ ! $mynum -eq 200 ]
then
echo c
else
echo "The variable does not equal 200. "
fi
Salida:
The condition is true.
Why?
The ! symbol reverses, flip around, negates the text, so if it was true before now it is
false and viceversa. in this case the expected result should be "The variable does not
equal 200. " but beacuse of the ! symbol we got The variable does not equal 200. "
With the ! symbol the function will do the opposite that would do normally.
if [ $mynum is not equal to 200 ]
Anyway in this case in particular this is not the best way to express in code.
We can use simple 'ne' which means 'not equal'.
if [ $mynum -ne 200 ]
Greater than. If $mynum is greater than:
if [ $mynum -gt 200 ]
Viendo si un archivo existe:
el símbolo ~ significa mi home directory, es decir /home/emm/
-f stands for file. -D stands for Directory.
#!/bin/bash
if [ -f ~/myfile ]
then
echo "The file exists."
else
echo "The file does not exist."
fi
Salida:
$ ./[Link]
The file does not exist
Vamos a crear el archivo.
touch myfile
Ahora vemos la salida:
The file exists.
Probemos ahora con directorios:
#!/bin/bash
if [ -d ~/my_directory ]
then
echo "The directory exists"
else
echo "The directory does not exist"
fi
Salida:
The directory does not exist
Vamos a crearlo:
mkdir my_directory
Corremos el script nuevamente y vemos la salida:
The directory exists
Comando which
este comando nos permite saber donde se encuentra alojado determinado comando.
por ejemplo:
which nano
Salida:
/usr/bin/nano
Veamos este ejemplo. Supongamos que sabemos la ruta por defecto de nano pero
estamos en otro sistema y no sabemos si está instalado y queremos tener la
herramienta.
#!/bin/bash
command=/usr/bin/nano
if [ -f $command ]
then
echo "$command is available, let's run it..."
else
echo "$command is NOT available, installing it..."
sudo apt update && sudo apt install -y nano
fi
$command
Primero asignamos la ruta a la variable comando. hacemos que chequee si el archivo
existe, si existe lo ejecuta al final y si no existe nos avisa y nos manda a hacer un
update y una instalación dando yes a todo, sin pedir confirmación.
The && command means if the first command is successful it runs the second. If the
first command fails, the second doesn't run.
-y means 'assume' yes and don't ask for confirmation.
You don´t want your scripts to ask for things, because the point is to automate tasks
without human intervention.
Important note:
Always when working with statements make sure there are spaces between [ and
numbers, strings or variables:
if [ ! $mynum -eq 200 ]
Otherwise you'll get error messages like this:
./[Link]: line 4: [: missing `]'
Another way of do the same:
El comando command -v (comando) lo que hace es ver si un comando existe, si un
comando está disponible, y de ser así muestra la ruta.
command -v nano
Salida:
/usr/bin/nano
#!/bin/bash
command=nano
if command -v $command
then
echo "$command is available, let's run it..."
else
echo "$command is NOT available, installing it..."
sudo apt update && sudo apt install -y $command
fi
$command
En este caso primero evalúa si el comando nano existe, si es así entonces da un
mensaje de que hay que correrlo y al final lo corre.
De no ser así lo instala, y luego lo corre.
Este código no necesita brackets en este caso, porque estamos usando otro comando, el
comando 'command'.
Cuando usamos brackets se asume que estamos usando el comando 'test' aunque no lo
escribamos, por defecto bash interpreta que estamos usándolo.
Las expresiones como -eq, -ne, -gt, etc, son argumentos del comando test y que
podemos usar, y de hecho ya hemos usado. Esto es interesante y si hacemos un man
test podemos ver que hay muchas argumentos para evaluar cosas en nuestro código y
que nos da true o false.
Dejo un ejemplo del uso de una evaluación de strings, se puede investigar más viendo
el man del comando test.
STRING1 = STRING2
the strings are equal
#!/bin/bash
string1="hola"
string2="hola"
if [ "$string1" = "$string2" ]
then
echo "Las cadenas son iguales."
else
echo "Las cadenas son diferentes."
fi
Salida:
Las cadenas son iguales.
Exit Codes
Los exit codes nos sirven para evaluar si un comando se ejecutó de manera exitosa o
no.
Podrá parecer algo banal utilizarlos ya que es obvio que algo salió bien o mal viendo
la pantalla. si nos da un error nos lo dirá, pero el tema es que la idea de los scripts es
automatizar y no que estemos pendientes de la pantalla.
Usar exit codes nos puede servir para que si algo no sale bien, se evalúen los exit
codes para por ejemplo enviarnos un mail avisándonos de ello.
Para saber un exit code de un comando es sencillo: se ejecuta un comando y luego la
expresión '$?' y eso nos dirá si el comando fue exitoso o no.
Todo exit code diferente de 0 significa que el comando ha fallado.
Notar como en estos ejemplos el fallido da 127 y el correcto da 0.
:~$ sldjajha
sldjajha: command not found
:~$ echo $?
127
:~$ cat .nanorc
set linenumbers
:~$ echo $?
0