partie du réseau
Apprenez les scripts bash en 27 minutes
Ceci est inspiré par Learn Go dans environ 5 minutes, une demi-heure pour apprendre la rouille et le zig en 30 minutes.
bash (Bourne Again Shell) a été développé en 1989, ce qui le rend plus jeune que C mais probablement plus âgé que tout ce que vous avez l'habitude de développer. Cela ne le rend pas à l'ancienne ou obsolète. Bash s'exécute pratiquement partout: sur Unix / Linux , sur MacOS et Windows (WSL), il est utilisé dans toutes sortes de logiciels `` modernes '' (docker, déploiement / construction de scripts, CI / CD) et les chances que vous ayez une riche carrière de développeur sans jamais utiliser bash est quasi zero. Alors pourquoi ne pas devenir bon dans ce domaine?
Chaque fois que vous tapez votre terminal / console, vous êtes dans une coquille bash interactive (ou ses cousins plus sophistiqués zsh ou fish ). Toute commande que vous pouvez taper ici, comme ls , whoami , echo "hello" se qualifie comme une commande bash et peut être utilisée dans un script.
Pendant que dans votre terminal, entrez la commande suivante (ne copiez pas le>, c'est là pour indiquer le début de la ligne de commande):
> touch myscript.sh # create the file 'myscript.sh' as an empty fileAllez modifier ce nouveau fichier avec votre éditeur de texte préféré (sublime / vcode / jetbrains / ...) et ajoutez les 2 lignes suivantes:
#! /usr/bin/env bash
echo " Hello world! "Maintenant, retournez à votre terminal et tapez
> 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 ! Les variables bash ne sont pas typées. La valeur et / ou le contexte d'une variable détermine s'il sera interprété comme un entier, une chaîne ou un tableau.
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 a un programme «test» essentiel (par exemple, test -f output.txt ) qui est le plus courant utilisé comme [[ -f output.txt ]] . Il existe également une syntaxe plus ancienne de [ -f output.txt ] , mais les supports doubles sont préférés. Ce programme teste pour une certaine condition et revient avec 0 ('ok') si la condition était remplie. Le but de cela deviendra clair dans le chapitre suivant.
[[ -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 Chaque script, fonction, programme a 3 flux par défaut (descripteurs de fichiers): stdin, stdout et stderr. Par exemple, «tri» est un programme qui lit des lignes de texte sur STDIN et les publie triée sur STDOUT, et affiche toutes les erreurs qu'il rencontre dans 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 Le | (Pipe) Le personnage est la superpuissance de Bash. Il vous permet de construire des chaînes de programmes sophistiquées, où chacun passe son stdout au stdin du programme suivant. Si la philosophie UNIX prescrit " des programmes d'écriture qui font une chose et le font bien ", alors Bash est l'outil parfait pour coller tous ces programmes spécialisés ensemble. Pour trier, utiliser, sort , rechercher, utiliser grep , pour remplacer les caractères, utiliser tr ; Pour enchaîner tous ces éléments ensemble, utilisez Bash et ses tuyaux.
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 : Arrêtez le script lorsque des erreurs se produisent