Introdução

Desenho e Implementação de Unix (Linux)

Shell Unix

  • Uma shell é um programa que permite a interação entre o utilizador e o sistema UNIX:
    • Lê e analisa (parse) comandos do utilizador
    • Avalia caracteres especiais
    • Inicia pipes, redireções e processamento em background
    • Encontra e inicia programas para execução

História da Shell Unix

  • Há duas famílias de shell unix:
    • Bourne shell (AT&T) sh -> ksh-> bash
    • C shell (Berkeley) csh -> tcsh
  • O nosso foco é na bash: sintaxe mais simples e é a shell default em muitos sistemas

Sistema de ficheiros

Ficheiros são organizados em diretórios, que, por sua vez são organizados numa estrutura hierárquica

Permissões

  • Ficheiros podem ter permissões para leitura, escrita e/ou execução

Exemplo

$ ls -l 
total 1452
drwxrwxr-x 4 ltorgo ltorgo    4096 Fev  5 23:58 Aula1
-rw-rw-r-- 1 ltorgo ltorgo     144 Fev 11  2016 makefile.txt
-rw-rw-r-- 1 ltorgo ltorgo     590 Fev 29  2016 solsF2.txt
-rw-rw-r-- 1 ltorgo ltorgo 1455567 Fev  5 17:39 Unix_vLT.pdf

Ficheiros

  • Podem ter tipos diferentes, normalmente identificados pela extensão
  • Tipos estão relacionados com o formato dos ficheiros
  • Por exemplo, ficheiros com extensão doc ou docx estão em formato editável pelo Microsoft Office, LibreOffice ou OpenOffice
  • Ficheiros com extensão txt estão em formato texto ASCII

American Standard Code for Information Interchange (ascii)

Unicode (utf-8, utf-16, …)

  • ASCII define 128 carateres
  • O Unicode é um super-conjunto do ASCII, que usa os mesmos códigos nos primeiros 128 carateres
  • Possibilidade de codificar muitos mais carateres

Extensões típicas de ficheiros

Comandos básicos do Unix

  • cd dir – troca para o diretório dir
  • cd .. – troca para um diretório acima (“..”)
  • cd ~ - troca para o diretório “home” (“~”)
  • cp -i file1 file2 - copiar file1 para file2
  • mv -i file1 path – mover file1 para o local path
  • rm -i file1 – remover file1
  • cat file1 - imprimir file1
  • mkdir dir – criar o diretório dir
  • ls dir – mostrar o conteúdo do diretório dir

O que é e por que utilizar a opção -i?

  • Para garantir que ficheiros não são removidos ou alterados por engano!

Formato geral de um comando bash

  • cmd arg\(_1\) arg\(_2\) … arg\(_n\)
  • Input from stdin (teclado), Output to stdout (ecrã)
  • cmd > file redireciona a saída padrão (ecrã) para um ficheiro (escreve num ficheiro)
  • cmd >> file redireciona a saída padrão para um ficheiro (concatena)
  • cmd < file executa cmd lendo a entrada de um ficheiro

Comandos Gerais da bash

echo 'Bem vindos a Laboratório de Computadores!' > input
tr '[:lower:]'  '[:upper:]' < input >> output
cat output
BEM VINDOS A LABORATÓRIO DE COMPUTADORES!
BEM VINDOS A LABORATóRIO DE COMPUTADORES!
BEM VINDOS A LABORATóRIO DE COMPUTADORES!
BEM VINDOS A LABORATóRIO DE COMPUTADORES!
BEM VINDOS A LABORATóRIO DE COMPUTADORES!
BEM VINDOS A LABORATóRIO DE COMPUTADORES!
BEM VINDOS A LABORATóRIO DE COMPUTADORES!
BEM VINDOS A LABORATÓRIO DE COMPUTADORES!
BEM VINDOS A LABORATÓRIO DE COMPUTADORES!
BEM VINDOS A LABORATÓRIO DE COMPUTADORES!
BEM VINDOS A LABORATÓRIO DE COMPUTADORES!
BEM VINDOS A LABORATÓRIO DE COMPUTADORES!
BEM VINDOS A LABORATóRIO DE COMPUTADORES!
BEM VINDOS A LABORATóRIO DE COMPUTADORES!
BEM VINDOS A LABORATóRIO DE COMPUTADORES!
BEM VINDOS A LABORATóRIO DE COMPUTADORES!

Concatenou o texto “BEM VINDOS A LABORATÓRIO DE COMPUTADORES!” ao conteúdo do ficheiro output

Piping e Redirecionamento

  • cmd1 | cmd2 executa cmd1 e envia sua saída diretamente ao comando cmd2
  • Composição de pipes:
    cmd1 < file1 | cmd2 | cmd3 | cmd4 > file2

Exemplo:

echo "Há cinco palavras nesta frase" | wc -w
5
  • Podemos redirecionar as mensagens de erro para um ficheiro
    • cmd 2> command.error
    • cmd 2>> comand.error
  • Podemos redirecionar tanto o ouput como as mensagens de erro para o mesmo ficheiro
    • cmd &> output
  • Podemos redirecionar para /dev/null para suprimir todo o output
  • Porque é que o seguinte não funciona corretamente?
    • cmd < file > file
  • Porque antes do comando ser executado o ficheiro é aberto para leitura e escrita. Quando é aberto para escrita é “limpo”.

  • O que é que o seguinte comando imprime?

    echo '1337 5p34k !5 n07 5p0k3n 4m0n9 2341 h4ck325' | tr '01234579!' 'olreastgi'

Códigos de terminação de execução

  • Quando um comando termina, sempre envia um código de saída (entre 0 e 255)
  • Este código é armazenado na variável $?
  • O código 0 significa que o comando terminou de forma bem sucedida
  • A página de manual de cada comando (man command) diz os códigos que podem ser retornados

  • Exemplo: grep retorna código 0 se encontrar pelo menos um “match”:

ls -l / | grep bin   # "/" é o diretório raíz
echo $?
drwxr-xr-x   2 root root  4096 Fev 23 12:05 bin
drwxr-xr-x   2 root root 12288 Mar 31 11:07 sbin
0

Expressões Regulares

  • Permitem rapidamente encontrar padrões em textos

egrep

Caracter Significado Exemplo Match No Match
^ Princípio da linha ^g gato o gato
$ Fim da linha o$ gato gata
. Qualquer carater .. Qualquer string com pelo menos 2 carateres a
? Carater opcional ga?o gato, gao gata
() Grupo de carateres g(at)o gato gao, go, gto
[] Grupo de carateres opcional g[at]o gao, gto gato, go
- Intervalo de carateres g[a-c]o gate, gbte, gcte gdte, gaate
+ Um ou mais dos carateres precedentes gato[1-3]+ gato1, gato13, gato112 gato, gato4
* Zero ou mais dos carateres precedentes gato[1-3]* gato, gato13, gato112 gato4
{,} Número de repetições a{2,5} aa, aaaaa a, xx3
\ Carater tratado literalmente 20\*3 20*3 203
(|) Opções (gato|gata) gato, gata cão
  • Exemplos:

    • String a começar por uma letra maiúscula:
      ^[A-Z].*
      Possíveis matches:

      The gate is open
      T
    • Testar códigos postais:
      ^[0-9]{4}(\-[0-9]{3})?$
      Possíveis matches:

      4150-030
      4100
    • Qualquer string contendo o caracter @ que termine com .com
      ^.+@.+\.com$
      Possíveis matches:

      xpto@company.com

Expansão de Nomes de Ficheiros

Num shell, se digitarmos:

echo Isto é um teste

O resultado é:

## Isto é um teste

Porém, se digitarmos:

echo *

O resultado é:

about.html about.Rmd biblio.html biblio.Rmd dates.html dates.Rmd eval.html eval.Rmd Exemplos Figuras images index.html index.Rmd info.html info.Rmd input LabC1617.Rproj notasTeste_files notasTeste.html notasTeste.Rmd output plan.html plan.Rmd projecto-de-laboratorio.pdf projeto.html projeto.Rmd shell.html shell.Rmd site_libs _site.yml Slides Unix.html Unix.Rmd

Porquê?

  • A shell substitui o caracter * por todos os ficheiros no diretório corrente.
  • Este é um exemplo de expansão do caminho (path), um tipo de expansão usada na shell.

Interpretando caracteres especiais

  • Caracteres especiais:
    $ * < > & ? f g [ ]
  • A shell interpreta estes caracteres de forma especial, a menos que coloquemos uma barra antes do caracter (escape character) (\$) ou entre aspas “$”.
  • Quando invocamos um comando, a shell primeiro traduz os caracteres da linha de comando para o comando UNIX correspondente
  • O poder de um script shell vem da capacidade da shell interpretar e expandir comandos
  • A shell interpreta o carater $ de maneira especial
  • Se var é uma variável, então $var é o valor guardado nessa variável
  • Se cmd é um comando, então $(cmd) é traduzido para o resultado do comando cmd
echo $USER
ltorgo
echo $(pwd)
/usersData/ltorgo/Dropbox/DropboxHome/Ensino/Licenciaturas/LaboratorioComputadores/WebPage
  • * ^ ? f g [ ] são conhecidos como wildcard characters que a shell usa para fazer matching com:
    • * faz matching com qualquer string, i.e. 0 ou mais carateres:
    Padrão Faz matching Não faz matching
    Lec* Lecture1.pdf Lec.avi ALecBaldwin/
    L*ure* Lecture2.pdf Lectures/ sure.txt
    *.tex Lecture1.tex Presentation.tex tex/
    • ? faz macthing com um único carater
    Padrão Faz matching Não faz matching
    Lecture?.pdf Lecture1.pdf Lecture2.pdf Lecture11.pdf
    ca? cat can cap ca cake
    • [...] faz matching com qualquer carater que esteja dentro dos parenteses
    • Pode-se usar um - para indicar ranges de carateres
    • Podemos colocar vírgulas entre carateres ou ranges de carateres

Quoting

Se não queremos que a shell interprete os carateres especiais podemos usar aspas (quoting)

  • Single Quotes: nenhum carater especial é avaliado
echo '$USER owes me $ 1.00'
$USER owes me $ 1.00
  • Double Quotes: só é feita substituição de variáveis e comandos
echo "$USER owes me $ 1.00"
ltorgo owes me $ 1.00
  • Back Quotes: é executado o comando entre as aspas
echo "I am $USER and today is `date`"
I am ltorgo and today is Qua Abr 19 15:43:38 WEST 2017

Ferramentas Unix

Ferramentas essenciais para parsing de texto e dados: - cat - less - tr - sort - grep - sed - gawk - head - tail - wc - uniq

O sed e o gawk fornecem por si só linguagens

O comando grep

  • grep -i - ignora maiúsculas/minúsculas
  • grep -A 20 -B 10 - escreve 10 linhas antes e 20 linhas depois de cada match
  • grep -v - inverte o match
  • grep -o - mostra somente a substring que fez match
  • grep -n - mostra o nº de linha
grep '[Mm]onster' Frankenstein.txt | wc -l

Mostrar conteúdo de ficheiros

  • cat, head, tail e less
    • cat file - prints the contents of file
    • cat file1 file2 - prints the contents of file1 then file2 to stdout
    • head -n 20 file - prints the first 20 lines (default is 10)
    • tail -n 20 file - prints the last 20 lines
    • tail -f file - keeps outputting appended data
    • less file - fits the output to the terminal and allows one to scroll.

Traduzir carateres

  • O comando translate traduz um conjunto de carateres para outro
  • tr aeiou AEIOU < file - outputs the contents of the file with all vowels capitalized.
  • tr -d '!@#$%^&*' <file - deletes the specified characters.
  • tr [A-Z] [a-z] < file- outputs a lowercase version of the file.

  • Exemplo:

echo "$USER is my username, but its more interesting without vowels" | tr -d aeiouAEIOU
ltrg s my srnm, bt ts mr ntrstng wtht vwls

Ordenação

  • O comando sort ordena as linhas de um ficheiro de texto alfabeticamente

  • sort -r u file- sorts the file in reverse order and deletes duplicate lines.
  • sort -n -k 2 -t - file sorts the file numerically by using the second column, separated by a colon

  • Exemplo:

echo -e "62\n5\n1\n11\n8" | sort -n
1
5
8
11
62

Contagem

  • O comando wc mostra o nº de linhas, palavras e bytes num ficheiro

  • wc -l <file prints the number of lines in the file.
  • wc -w <file prints the number of words in the file.

echo How many words in this sentence? | wc -w
6

Alias

  • À medida que vamos usando a Bash vamo-nos apercebendo que há comandos que usamos muitas vezes
  • Por exemplo ls -l para listar os ficheiros e ver as permissões
  • Ou rm -i para garantir que não apagamos sem querer ficheiros.
  • Os alias permitem atribuir nomes simples a estes comandos+opções que usamos frequentemente para nos poupar tempo de escrita.

  • Usam-se fazendo:

alias nome=comando

  • É um forma de atribuirmos um nome mais simples a um comando complicado que fazemos muitas vezes
  • Podemos criar alias em qualquer altura na linha de comando da bash
  • Para o fazer de forma permanente podemos acrescentar o comando de criação do alias ao ficheiro .bashrc ou ao ficheiro .bash_profile

Exemplos:

alias ls='ls --color=auto'
alias rm='rm -i'
alias ll='ls -l' 
  • Quotes are necessary if the string being aliased is more than one word
  • To see what aliases are active simply type alias
  • Note: If you are poking around in .bashrc you should know that # is the UNIX comment character. So any line that starts with # is commented out (with the exception of the first line of scripts that start with the pair #!)

O editor sed

  • sed is a stream editor. We will only cover the basics, as it is a completely programming language!

  • sed 's/regexp/txt/g' - substitution
    sed 's/not guilty/guilty/g' filename
  • What happens if we don’t have the g?

  • sed '/regexp/d' - deletion
    sed '/[Dd]avid/d' filename > filename2

  • deletes all lines that contain either David or david and saves the file as filename2.

-Sed is designed to be useful especially if: + your files are too large for comfortable interactive editing + your sequence of editing commands is too complicated to be comfortably typed in interactive mode + you want to globally apply your edits in one pass through

  • The power of sed is that it treats everything between the first pair of ‘/s as a regular expression. So we could do
    sed s/[[:alpha:]]\{1,3\}[[:digits:]]*@up\.pt/porto email removed/g' file

to print a file with all UPorto email addresses removed.

  • use -r to use extended regular expressions.

  • Besides substitution and deletion we can use sed to
    • append lines
    • change lines
    • insert
    • print lines
    • among other things
  • Sed is a complete programming language. In fact people have written entire games as sed scripts. Check http://aurelio.net/soft/sedarkanoid/

Shell Scripts

  • Um (bash) script shell é um ficheiro que contém texto que segue as seguintes propriedades:
    • A primeira linha é #!/bin/bash (indica o shell a ser utilizado)
    • Ficheiro tem permissão de execução
  • Benefícios:
    • Reutilização e partilha de código
    • Geralmente, código menor e mais “limpo” que C, Java etc.
  • Um primeiro exemplo simples de um script:
    • Vamos criar o ficheiro OlaMundo.sh com o seguinte conteúdo:

      #! /bin/bash
      echo “Olá, meu nome é $USER, gostaria de dizer Olá ao mundo usando $SHELL em $HOSTNAME, uma $MACHTYPE máquina. "
  • Quando terminar de editar este ficheiro, mude as permissões: chmod +x OlaMundo.sh para que este fique executável.

Variáveis

  • Variables are denoted by $varname, and set by varname=value
  • No spaces!
  • Example:
world=Earth
echo "Yo $world"
Yo Earth
  • There are a ton of built-in variables ($USER $SHELL … etc)

Variáveis especiais

  • $0, $1, $2, …, ${10}, ${11}, etc. are positional parameters, passed from command line to script, passed to a function, or set to a variable
  • $0 - contains the name of the script being executed
  • $# number of command-line arguments or positional parameters
  • $* nll of the positional parameters, seen as a single word. “$*" expands to "$1 $2 ... $n"
  • $@ same as $*, but each parameter in the argument list is seen as a separate word. "$@" expands to "$1" "$2" ... "$n"
  • You almost always want to use $@ (see why later)
  • $? - exit code of the last program executed
  • $$ - current process id

  • Um exemplo simples:

#!/bin/bash
tr ' ' '\n' $1 | grep '^[[:upper:]]' | wc -l
  • $1 refers to the first argument passed to the script
  • '^[[:upper:]]' is a regular expression.
  • ^ refers to the beginning of a line and [[:upper:]] is any uppercase letter.

Aritmética

  • Bash will do math when it is placed within double parenthesis (( )).
  • A math expression returns 0 if the value is nonzero and 1 if the value is zero (wonderful isn’t it? ;-))
  • If we want to echo the math we need to do $((math ))
  • Inside (( )) variable substitution is done automatically (don’t need $)

  • Examples:

(( 1 + 2 )); echo $?
0
(( 0 )); echo $?
1
(( 1 > 2 )); echo $?
1

A instrução if

A estruturação do if pode ser a seguinte:

if cmd1
then
  cmd2
  cmd3
elif cmd4
then
  cmd5
else
  cmd6
fi

Ou:

if cmd1
then cmd2; cmd3
elif cmd4
then cmd5
else cmd6
fi
  • Each conditional statement evaluates as true if the cmd executes successfully (returns an exit code of 0)
  • Can use a ; instead of hitting enter for a newline

  • Alguns exemplos simples:

if cmp file1 file2
then
    echo "Files are the same"
else
    echo "Files are different"
fi
if grep -q bash $1
then echo "There is at least one instance of Bash in $1"
fi
#! /bin/bash
# This script searches a file for some text then
# tells the user if it is found or not.
# If it is not found, the text is appended
if grep -q "$1" $2
then
    echo "$1 found in file $2"
else
    echo "$1 not found in file $2, appending."
    echo $1 >> $2
fi

Expressões em testes

  • We would not get very far if all we could do was test with exit codes. Fortunately bash has a special set of commands of the form [ testexp ] that perform the test testexp. First to compare two numbers:
    • n1 -eq n2 - tests if n1 = n2
    • n1 -ne n2 - tests if n1 != n2
    • n1 -lt n2 - tests if n1 < n2
    • n1 -le n2 - tests if n1 <= n2
    • n1 -gt n2 - tests if n1 > n2
    • n1 -ge n2 - tests if n1 >= n2
  • If either n1 or n2 is not a number, the test fails.

  • Exemplo:

#! /bin/bash
# Created on [2/20/2009] by David Slater
# Purpose of Script: Searches a file for two strings and prints which is more frequent
# Usage: ./ifeq.sh <file> string1 string2
arg=`grep $2 $1 | wc -l`
arg2=`grep $3 $1 | wc -l`
if [ $arg -lt $arg2 ]
then
    echo "$3 is more frequent"
elif [ $arg -eq $arg2 ]
then
    echo "Equally frequent"
else
    echo "$2 is more frequent"
fi 

Note: Could have used (( $arg < $arg2 )) and (( $ arg == $arg2 ))

Comparação de Strings

  • To perform tests on strings use
    • s1 == s2 - s1 and s2 are identical
    • s1 != s2 - s1 and s2 are different
    • `s1 - s1 is not the null string
  • Make sure you leave spaces! s1==s2 will fail!

  • You can combine tests:

    if [[ testexp1 && testexp2 ]]
    then
    cmd
    fi
  • && - and ( -a for test )
  • || - or ( -o for test )
  • ! testexp1 - not (same for test)

Testes de Paths

  • If path is a string indicating a path, we can test if it is a valid path, the type of file it represents and the type of permissions associated with it:
    • -e path - tests if path exists
    • -f path - tests if path is a regular file
    • -d path - tests if path is a directory
    • -r path - tests if you have permission to read the file
    • -w path - tests if you have write permission
    • -x path - tests if you have execute permission

[[ versus [

  • If you have done some scripting before, or looked at scripts, sometimes you may see people using [[ instead of [.
  • [ is a synonym for test.
  • `[[ is a new improved version. They have a lot in common, but have a few differences

  • string comparison:
    • [[ uses > ; [ uses \>
    • [[ uses < ; [ uses \<
  • [[ uses && and || ; [ uses -a and -o
  • [[ uses =~ for regular expression matching while [ cannot match regular expressions
  • [[ uses = for pattern matching while [ cannot do pattern matching

  • Exemplos:

[[ $name = a* ]] || echo "name does not start with an 'a': $name"
[[ $(date) =~ ^Fri\ ...\ 13 ]] \ 
&& echo "It's Friday the 13th!"

Ciclos

While

while cmd
do
    cmd1
    cmd2
done
  • Executes cmd1, cmd2 as long as cmd is successful (i.e. its exit code is 0).

  • Exemplo:

i=1
while [[ $i -le 10 ]]
do
    echo $i
    i=$(($i+1))
done
  • This loop prints all numbers 1 to 10.
  • We could have done while (( i <= 10))

Until

until cmd
do
    cmd1
    cmd2
done
  • Executes cmd1, cmd2 as long as cmd is unsuccessful (i.e. its exit code is not 0).

  • Exemplo:

i=1
until [[ $i -ge 11 ]]
do
    echo i is $i
    i=$(($i+1))
done

For

for var in string1 string2 ... stringn
do
    cmd1
    cmd2
done
  • The for loop actually has a variety of syntax it can accept. We will look at each in turn.

  • Exemplo:

#! /bin/bash
# lcountgood.sh
i=0
for f in "$@"
do
    j=`wc -l < $f`
    i=$(($i+$j))
done
echo $i
  • This script counts lines in a collection of files. For instance, to count the number of lines of all the files in your current directory just run ./lcountgood.sh *

  • What happens if we change $@ to $*?

#! /bin/bash
# lcountbad.sh
i=0
for f in "$*"
do
    j=`wc -l < $f`
    i=$(($i+$j))
done
echo $i
  • This does not work! Why?

  • We can also do things like:

    for i in {1..10}
    do
    echo $i
    done
  • To print 1 to 10.
  • bash expands {1..10} before the for loop executes.
  • Syntax: {start..end..increment}

Ler Input do Utilizador

$ read -p "How many apples do you have? " apples
How many apples do you have? 5
$ echo $apples
5
  • We can also use read to loop over lines of input.
cat datafile | while read line
do
    if (( $line < 10 ))
    then
        echo $line
    fi
done