parte de la red
Aprende Bash Scripting en 27 minutos
Esto se inspira en Learn Go en ~ 5 minutos, media hora para aprender óxido y zig en 30 minutos.
bash (Bourne Again Shell) se desarrolló en 1989, lo que hace que sea más joven que C, pero probablemente más viejo que cualquier cosa en la que esté acostumbrado. Esto no lo hace anticuado u obsoleto. Bash se ejecuta prácticamente en todas partes: en Unix/Linux , en MacOS y Windows (WSL), se usa en todo tipo de software 'moderno' (Docker, implementación/construcción de scripts, CI/CD) y las posibilidades de que tenga una rica carrera de desarrolladores sin usar bash son cuasi cero. Entonces, ¿por qué no ser bueno en eso?
Siempre que esté escribiendo en su terminal/consola, se encuentra en una cáscara bash interactiva (o sus primos más sofisticados zsh o fish ). Cualquier comando que pueda escribir aquí, como ls , whoami , echo "hello" califica como un comando bash, y puede usarse en un script.
Mientras esté en su terminal, ingrese el siguiente comando (no copie el>, está allí para indicar el inicio de la línea de comando):
> touch myscript.sh # create the file 'myscript.sh' as an empty fileVaya a editar este nuevo archivo con su editor de texto favorito (sublime/vcode/jetbrains/...) y agregue las siguientes 2 líneas:
#! /usr/bin/env bash
echo " Hello world! "Ahora vuelve a su terminal y escriba
> chmod +x myscript.sh # make the file executable, so you can call it directly as ./myscript.sh
> ./myscript.sh # execute your new script
Hello world ! Las variables bash no tienen tipo. El valor y/o el contexto de una variable determina si se interpretará como un entero, una cadena o una matriz.
width=800 # variables are assigned with '='
name= " James Bond " # strings with spaces should be delimited by " or '
user_name1=jbond # variable names can contain letters, digits and '_', but cannot start with a digit
echo " Welcome $name ! " # variable are referenced with a $ prefix
file= " ${user} _ ${uniq} " # ${var} can be used to clearly delimit the name of the variable
echo " ${width :- 400} " # if variable $width is not set, the default 400 will be used
echo " ${text / etc / &} " # replace the 1st text 'etc' by '&' in the variable before printing it
echo " ${text // etc / &} " # replace all texts 'etc' by '&' in the variable before printing it
w= $(( width + 80 )) # $(()) allows arithmetic: + - / * %
input= $1 # $1, $2 ... are the 1st, 2nd ... parameters specified on the command line
input= " $1 " # put quotes around any variable that might contain " " (space), "t" (tab), "n" (new line)
script= $0 # $0 refers to the actual script's name, as called (so /full/path/script or ../src/script)
temp= " /tmp/ $$ .txt " # $$ is the id of this process and will be different each time the script runs
echo " $SECONDS secs " # there are preset variables that your shell sets automatically: $SECONDS, $HOME, $HOSTNAME, $PWD
LANG=C do_something # start the subcommand do_something but first set LANG to "C" only for that subcommand
script= $( basename " $0 " ) # execute what is between $( ) and use the output as the value Bash tiene un programa esencial de 'prueba' (por ejemplo, test -f output.txt ) que se usa más común como [[ -f output.txt ]] . También hay una sintaxis anterior de [ -f output.txt ] , pero se prefieren los soportes cuadrados dobles. Este programa prueba para una determinada condición y devuelve con 0 ('OK') si se cumplió la condición. El propósito de esto será claro en el próximo capítulo.
[[ -f file.txt ]] # file exists
[[ ! -f file.txt ]] # file does not exist -- ! means 'not'
[[ -f a.txt && -f b.txt ]] # both files exist -- && means AND , || means OR
[[ -d ~ /.home ]] # folder exists
[[ -x program ]] # program exists and is executable
[[ -s file.txt ]] # file exists and has a size > 0
[[ -n " $text " ]] # variable $text is not empty
[[ -z " $text " ]] # variable $text is empty
[[ " $text " == " yes " ]] # variable $text == "yes"
[[ $width -eq 800 ]] # $width is the number 800
[[ $width -gt 800 ]] # $width is greater than 800
[[ file1 -nt file2 ]] # file1 is newer (more recently modified) than file2 if [[ ! -f " out.txt " ]] ; then # if ... then ... else ... fi
echo " OK "
else
echo " STOP "
fi
[[ -f " out.txt " ]] && echo " OK " || echo " STOP " # can also be written as 1 line if the 'then' part is 1 line only
while [[ ! -f output.txt ]] ; do # while ... do ... done
(...) # wait for output.txt
continue # return and do next iteration
done
for file in * .txt ; do # for ... in ... do ... done
echo " Process file $file "
(...)
done
for (( i = 0 ; i < n; i ++ )) ; do # for (...) do ... done
(...)
done
case $option in # case ... in ...) ;; esac
export) do_export " $1 " " $2 " # you might know this as a 'switch' statement
;;
refresh) do_refresh " $2 "
;;
* ) echo " Unknown option [ $option ] "
esac myfunction (){ # bash functions are defined with <name>(){...} and have to be defined before they are used
# $1 = input # functions can be called with their own parameters, and they are also referenced as $1 $2
# $2 = output # this means that the main program's $1,$2...parameters are no longer available inside the function
local error # a variable can be defined with local scope. if not, variables are always global
(...)
return 0 # this explicitly exits the function with a status code (0 = OK, > 0 = with an error)
}numbers=(1 2 3) # define array with all values
numbers[0]= " one " # replace 1st element (indexes start at 0) by "one"
echo ${numbers[@]} # [@] represents the whole array
numbers=( ${numbers[@]} 4) # add new element to array
${ # numbers[@]} # nb of elements in the array
for element in ${numbers[@]} ; do
...
done Cada script, función, programa tiene 3 transmisiones predeterminadas (descriptores de archivos): Stdin, Stdout y Stderr. Por ejemplo, 'Sort' es un programa que lee líneas de texto en Stdin y las genera ordenadas en Stdout, y muestra cualquier error que encuentre en Stderr.
# by default, `stdin` is your interactive terminal, `stdout` and `stderr` are both your terminal
sort # stdin = read from terminal (just type and end with CTRL-D), stdout = terminal
< input.txt sort # stdin = read from input.txt, stdout = terminal
< input.txt sort > sorted.txt # stdin = read from input.txt, stdout = written to sorted.txt
< input.txt sort >> sorted.txt # stdin = read from input.txt, stdout = append to sorted.txt
< input.txt sort > /dev/null # stdin = read from input.txt, stdout = just ignore it, throw it away
echo " Output " # writes "Output" to stdout = terminal
echo " Output " >&2 # writes "Output" to stderr = terminal
program 2> /dev/null > output.txt # write stdout to output.txt, and ignore stderr
program & > /output.txt # redirect both stdout and stderr to output.txt
find . -name " *.txt "
| while read -r file ; do # while read is a good way to run some code for each line
output= " $( basename " $file " .txt ) .out "
[[ ! -f " $output " ]] && < " $file " sort > " $output "
done El | (tubería) El personaje es la superpotencia de Bash. Le permite construir cadenas sofisticadas de programas, donde cada uno pasa su stdout al stdin del próximo programa. Si la filosofía de Unix prescribe " Escribir programas que hacen una cosa y lo hacen bien ", entonces Bash es la herramienta perfecta para pegar todos esos programas especializados juntos. Para ordenar, usar sort , buscar, usar grep , reemplazar los caracteres, usar tr ; Para encadenar todo esto juntos, use Bash y sus tuberías.
ls | sort | head -1 # ls lists filenames to its stdout, which is 'piped' (connected) to sort's stdin.
# sort sends the sorted names to its stdout, which is piped to stdin of 'head -1'.
# head will just copy the first line from stdin to stdout and then stop
# the following chain will return the 5 most occurring non-comment lines in all .txt files
cat * .txt | grep -v ' ^# ' | sort | uniq -c | sort -nr | head -5
# this line gives a lowercase name for the current script (MyScript.sh -> myscript)
script_name= $( basename " $0 " .sh | tr " [:upper:] " " [:lower:] " ) ( # ( ... ) starts a new subshell with its own stdin/stdout
cat * .txt
curl -s https://host/archive.txt
) | sort
start_in_background & # start the program and return immediately, don't wait for it to end
git commit -a && git push # 'git push' will only execute if 'git commit -a' finished without errors set -uo pipefail : detenga el script cuando ocurran errores