parte da rede
Aprenda scripts bash em 27 minutos
Isso é inspirado pelo aprendizado, entre ~ 5 minutos, meia hora para aprender ferrugem e zigue-zague em 30 minutos.
bash (Bourne Again Shell) foi desenvolvido em 1989, o que o torna mais jovem que C, mas provavelmente mais velho do que qualquer coisa que você está acostumado a se desenvolver. Isso não o torna antiquado ou obsoleto. O Bash funciona praticamente em todos os lugares: no Unix/Linux , no macOS e Windows (WSL), é usado em todos os tipos de software 'moderno' (Docker, Scripts de implantação/construção, CI/CD) e as chances de que você tenha uma rica carreira de desenvolvedor sem nunca usar bash são quasi zero. Então, por que não ficar bom nisso?
Sempre que você estiver digitando em seu terminal/console, você está em uma bash interativa (ou em seus primos mais sofisticados zsh ou fish ). Qualquer comando que você possa digitar aqui, como ls , whoami , echo "hello" se qualifica como um comando bash e pode ser usado em um script.
Enquanto estiver no seu terminal, digite o seguinte comando (não copie o>, ele está lá para indicar o início da linha de comando):
> touch myscript.sh # create the file 'myscript.sh' as an empty fileVá editar este novo arquivo com seu editor de texto favorito (sublime/vcode/jetbrains/...) e adicione as 2 linhas a seguir:
#! /usr/bin/env bash
echo " Hello world! "Agora volte ao seu terminal e digite
> 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 ! Variáveis de bash não são criadas. O valor e/ou o contexto de uma variável determina se será interpretada como um número inteiro, uma string ou uma 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 O BASH possui um programa essencial de 'teste' (por exemplo, test -f output.txt ) que é mais comum usado como [[ -f output.txt ]] . Há também uma sintaxe mais antiga de [ -f output.txt ] , mas os suportes quadrados duplos são preferidos. Este programa testa uma determinada condição e retorna com 0 ('ok') se a condição foi atendida. O objetivo disso ficará claro no 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, função, programa possui 3 fluxos padrão (descritores de arquivos): stdin, stdout e stderr. Por exemplo, 'Sort' é um programa que lê linhas de texto no stdin e as produzem classificadas no stdout e mostra quaisquer erros encontrados no 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 O | (Pipe) O personagem é a superpotência de Bash. Ele permite que você construa cadeias sofisticadas de programas, onde cada uma passa seu stdout para o próximo stdin do programa. Se a filosofia do UNIX prescrever " Escreva programas que façam uma coisa e o façam bem ", o Bash é a ferramenta perfeita para colar todos esses programas especializados juntos. Para classificar, use sort , para pesquisar, usar grep , substituir os caracteres, usar tr ; Para encadear tudo isso, use Bash e seus tubos.
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 : Pare o script quando os erros acontecer