Prompt-doc: “Tira Dúvidas” sobre Shell

Conectiva - Curitiba, 4 de Dezembro de 2003

Este é o histórico da linha de comando de uma palestra que fiz para funcionários da Conectiva, sobre Shell Script. O objetivo não era ensinar Shell, mas sim passar dicas e sanar as dúvidas dos participantes, que já conheciam a linguagem e já faziam scripts.

  • Data: 04-Dez-2003
  • Local: Auditório da Conectiva, Curitiba
  • Duração: 2 horas
  • Requisitos: Conhecer o shell, já ter feito scripts

Shell scripts no sistema (exemplos!)

$ cd /usr/bin
$ file * | grep -i shell
$ vi xtrace

Como executar um script (chmod)

$ cd /tmp
$ vi teste.sh
$ ./teste.sh
$ ls -l teste.sh
$ chmod +x teste.sh
$ ls -l teste.sh
$ ./teste.sh
$ vi teste.sh
$ which sh
$ l /bin/sh
$ vi teste.sh
$ ./teste.sh
$ vi teste.sh

Expansão de variáveis com ${VAR:-} e amigos

$ a="abcde"
$ echo $a
$ echo ${a}
$ echo ${#a}
$ echo ${a:-FOO}
$ unset a
$ echo $a
$ echo ${a:-FOO}
$ if [ -z "$a" ]; then a=FOO ; fi
$ unset a
$ echo $a
$ echo ${a:-FOO}
$ echo ${a:=FOO}
$ echo $a
$ echo ${a:+FOOoooooooo}

Expansão avançada do bash2 (tipo sed)

$ echo $a
$ echo ${a/O/.}      # sed s///
$ echo ${a//O/.}     # sed s///g
$ echo $a | sed 's/O/./g'
$ echo ${a//O/.tyturtu}
$ rpm -q bash
$ b=O
$ echo ${a//$b/.}

Eval

$ a="ls"
$ echo $a
$ eval $a
$ ${!a}
$ : ${!a}
$ echo ${!a}

Diferença do echo com aspas (mantém espaços) e sem

$ echo ahyi dfy dfui yidfs dfis ui       fd yifsdy idfsy isdf
$ echo "ahyi dfy dfui yidfs dfis ui       fd yifsdy idfsy isdf"
$ a="ahyi dfy dfui yidfs dfis ui       fd yifsdy idfsy isdf"
$ echo $a
$ echo "$a"
$ cat /etc/fstab
$ cat /etc/fstab | grep swap
$ cat /etc/fstab | grep swap | sed -n l
$ var=$(cat /etc/fstab | grep swap)
$ echo $var
$ echo "$var"

Subshell com crase ou $(), prefira o $()

$ var=`date`
$ echo $var
$ var=$(date)
$ echo $var
$ var=$(echo `cat /etc`)

As aspas simples protegem, não expandem vars nem comandos

$ a="abc"
$ echo $a
$ echo "$a"
$ echo '$a'
$ echo '$a $(date)'
$ echo "$a $(date)"

Ao definir uma variável não pode ter espaços!

$ a = ''

O pesadelo dos escapes...

$ a='\'
$ echo $a
$ a="\"
$ echo $a
$ echo \$a
$ a="\"
$ "
$ a=' \'    '
$ a="\\"
$ echo $a

O sed e os escapes (use o echo para ajudar!)

$ echo "//bla//"   # mudar para \\bla\\
$ echo "//bla//" | sed "s///\/"
$ echo "//bla//" | sed "s/\//\\/"
$ echo "s/\//\\/"
$ echo 's/\//\\/'
$ echo "//bla//" | sed 's/\//\\/'
$ echo "//bla//" | sed 's/\//\\/g'
$ a='/'
$ echo "//bla//" | sed "s/$a/\\/g"
$ echo "s/$a/\\/g"
$ a="\\/"
$ echo $a
$ echo "//bla//" | sed "s/$a/\\/g"
$ echo "s/$a/\\/g"
$ echo "//bla//" | sed "s/$a/\\\/g"
$ $(echo "//bla//" | sed "s/$a/\\\/g")
$ echo $(echo "//bla//" | sed "s/$a/\\\/g")

O sed pode usar qualquer delimitador fora o s///

$ echo isso | sed s/isso/aquilo/g
$ echo isso | sed s,isso,aquilo,g
$ echo isso | sed s isso aquilo g
$ echo isso | sed 's isso aquilo g'
$ echo isso | sed 's9isso9aquilo9g'
$ echo isso | sed 's
> isso
> aquilo
> g'
$ echo isso | sed 's|isso|aquilo|g'
$ echo isso | sed 'sáissoáaquiloág'
$ echo isso | sed 's§isso§aquilo§g'
$ echo isso | sed 's"isso"aquilo"'
$ echo isso | sed 's  isso    aquilo'
$ echo isso | sed 's  isso    aquilo  '

Como "ver" se é um TAB ou espaços

$ echo -e "\ta\ta"
$ echo -e "\ta\ta" | sed -n l
$ echo -e "\ta\ta" | od -c
$ echo -ne "\ta\ta" | od -c
$ echo -n "bla"
$ echo -ne "bla\n"
$ echo "bla"

Como depurar (debug) scripts: sh -x, set -x, ...

$ sh -x teste.sh
$ sh teste.sh
$ vi teste.sh
$ ./teste.sh
$ set -x
$ ./teste.sh
$ echo
$ vi teste.sh
$ ./teste.sh
$ vi teste.sh
$ set +x
$ vi teste.sh

Como pegar a saída de erro (STDERR, 2)

$ cp
$ cp | grep arqu
$ ls > foo
$ cat foo
$ cp > foo
$ cat foo
$ cp 1> foo
$ cp 1> foo 2> foo
$ cat foo
$ cp 2> foo
$ ./teste.sh
$ ./teste.sh 2> foo
$ ./teste.sh > foo
$ ./teste.sh > foo 2> foo
$ cat foo
$ ./teste.sh > foo 2>&1
$ cat foo
$ ./teste.sh > foo 2>&1
$ ./teste.sh 2>&1
$ cp
$ cp 2>&1
$ cp 2>&1 | grep arqui

O comando test, seu sósia [ e o código de retorno $?

$ if [ $var = 'abc' ] ; then echo OK ; fi
$ which [
$ l /usr/bin/[
$ if test $var = 'abc' ; then echo OK ; fi
$ if grep -qs root /etc/passwd ; then echo tem ; fi
$ grep -qs root /etc/passwd
$ echo $?
$ grep -qs roiiiiiiot /etc/passwd
$ echo $?
$ cp
$ echo $?
$ exit abnc
$ cp 2>/dev/null
$ echo $?
$ ls /dev/null

O [[ para fazer testes

$ if [ 1 -gt 5 ]; then echo é menor ; fi
$ if [ 8 -gt 5 ]; then echo é maior ; fi
$ if [[ 8 -gt 5 ]]; then echo é maior ; fi
$ if [[ 8  5 ]]; then echo é maior ; fi

Os operadores lógicos AND && e OR ||

$ cp 2>/dev/null ; echo $?
$ cp 2>/dev/null && echo OK
$ ls 2>/dev/null && echo OK
$ ls >/dev/null 2>&1 && echo OK
$ ls >/dev/null 2>&1 || echo OK
$ cp 2>/dev/null || echo OK
$ cp 2>/dev/null || echo OK && echo NOK
$ echo && echo OK || echo NOK
$ echo && cp 2>/dev/null || echo NOK
$ false && cp 2>/dev/null || echo NOK
$ false && cp || echo NOK
$ true && cp || echo NOK
$ false && cp || echo NOK
$ false && cp || echo NOK && echo OKDENOVO
$ false && { cp || echo NOK && echo OKDENOVO ; }
$ true && { cp || echo NOK && echo OKDENOVO ; }

Checagem de parâmetros da linha de comando ($1)

$ test -z "$1" || { echo uso: blabla ; exit 1  ; }
$ [ "$1" ] || { echo uso: blabla ; exit 1  ; }
$ [ "$1" ] || { echo uso: blabla ; echo exit 1  ; }
$ [ $1 ] || { echo uso: blabla ; echo exit 1  ; }
$ [ $1 = '--help' ] || { echo uso: blabla ; echo exit 1  ; }
$ [ "$1" = '--help' ] || { echo uso: blabla ; echo exit 1  ; }
$ [  = '--help' ] || { echo uso: blabla ; echo exit 1  ; }

Como passar parâmetros vazios

$ vi teste.sh
$ ./teste.sh
$ ./teste.sh ""
$ ./teste.sh "" dois
$ ./teste.sh "" "" dois

As ferramentas: cut

$ cat /etc/passwd | cut -d: -f5
$ cat /etc/passwd | cut -d: -f5,2
$ cat /etc/passwd | cut -d: -f5,2,1
$ cat /etc/passwd | cut -d: -f5-
$ cat /etc/passwd | cut -d: -f5-6
$ cat /etc/passwd | cut -d: -f5-7
$ cat /etc/passwd | cut -c 1-10
$ cat /etc/passwd | cut -c 10-

As ferramentas: awk

$ cat /etc/passwd | awk '{print $3}'
$ cat /etc/passwd | awk '{print $3}'
$ cat /etc/passwd | awk '{print $2}'
$ cat /etc/passwd | awk '{print $1}'
$ cat /etc/passwd | awk '{print $2}'
$ cat /etc/passwd | awk -F: '{print $2}'
$ cat /etc/fstab
$ cat /etc/fstab | cut -d" " -f4
$ cat /etc/fstab | awk '{print $4}'

As ferramentas: tr

$ a="asd asd       k          ioioio"
$ echo $a
$ echo "$a"
$ echo "$a" | tr -s ' '
$ echo aaaaabbbb | tr -s a
$ echo aaaaabbbb | tr -s ab
$ echo aaaaabbbb | tr a-z A-Z
$ echo aaaaabbbb | tr abcdef ABCDEF
$ echo aaaaabbbb | tr abcdef XVDGFFG

As ferramentas: sort

$ cat /etc/passwd
$ cat /etc/passwd | sort
$ cat /etc/passwd | sort -r

As ferramentas: rev, tac

$ cat /etc/passwd | rev
$ echo abcde | rev
$ echo cat | rev
$ tac /etc/passwd
$ tac /etc/passwd| rev

As ferramentas: sort, uniq

$ vi txt
$ cat txt | sort
$ cat txt | sort | uniq
$ cat txt | uniq
$ cat txt | sort -u
$ cat txt | sort | uniq

As ferramentas: wc

$ cat /etc/passwd | wc
$ cat /etc/passwd | wc -w
$ cat /etc/passwd | wc -l
$ cat /etc/passwd | wc -c

As ferramentas: cat, paste

$ vi txt2
$ cat txt txt2
$ paste txt txt2
$ paste -s txt txt2

As ferramentas: tee

$ echo abc
$ echo abc | sed 's/a/./'
$ echo abc | tee a | sed 's/a/./'
$ cat a

As ferramentas: head, tail

$ head /etc/passwd
$ head -2 /etc/passwd
$ tail -2 /etc/passwd
$ tail  /etc/passwd

As ferramentas: seq

$ for i in 1 2 3 4 5 5 6 7 8 9 10; do echo $i-- ; done
$ for i in 1 2 3 4 5 5 6 abd hjerer jrtj 8 9 10; do echo $i-- ; done
$ for i in $(seq 10); do echo $i-- ; done
$ seq 10
$ seq 2
$ seq 2 5
$ seq 5 2
$ seq 4 8 50

As ferramentas: printf

$ printf "%s" bla
$ printf "%s\n" bla
$ printf "%10s\n" bla
$ printf "%-10s\n" bla
$ printf "%10s----\n" bla
$ printf "%-10s----\n" bla
$ printf "%10s----\n" blaasdasdasdasd
$ printf "%d" 5
$ printf "%d\n" 5
$ printf "%4d\n" 5
$ printf "%4d\n" 5 | sed 's/ /0/g'
$ printf "%.4d\n" 5
$ printf "%4.2f\n" 5

As ferramentas: grep

$ cat /etc/passwd
$ cat /etc/passwd | grep root
$ cat /etc/passwd | grep -i root
$ cat /etc/passwd | grep -i ROOT
$ cp
$ echo $LANG
$ cat /etc/passwd | grep -w root
$ cat /etc/passwd | grep -w roo
$ cat /etc/passwd | grep -x roo
$ cat /etc/passwd | grep -l roo
$ grep -l roo /etc/passwd
$ grep -v roo /etc/passwd
$ grep -v root /etc/passwd
$ VAR=root
$ grep -i $VAR /etc/passwd
$ grep g /etc/passwd
$ grep g\$ /etc/passwd
$ fgrep g\$ /etc/passwd
$ fgrep g /etc/passwd
$ cd /bin
$ l grep egrep fgrep

As ferramentas: find

$ find . -type f
$ find . -type d
$ find . -type l
$ ln -s a z
$ find . -type l
$ find . -type f
$ find . -type f -exec echo rm -f {} \;
$ find . -type f -ok echo rm -f {} \;
$ find . -type f | while read BOZO; do echo $BOZO; done
$ cat /etc/passwd | while read BOZO; do echo $BOZO; done
$ cat /etc/passwd | while read BOZO; do echo {$BOZO}; done
$ cat /etc/passwd | while read BOZO; do echo $BOZO | grep -qs root && echo $BOZO; done
$ find . -type f -exec echo rm -f {}\;

As ferramentas: date

$ date
$ date +'%y %m %d'
$ date +'%Y %m %d'
$ date --help
$ date +'%Y-%m-%d'
$ date +'%Y-%m-%d %H:%M'
$ date +'hoje é %Y-%m-%d %H:%M ... '
$ date +'%s'
$ date +'%s'
$ date +'%s'

As ferramentas: diff, vi -d

$ cat txt txt2
$ diff txt txt2
$ vi txt2
$ cp txt txt3
$ vi txt3
$ diff txt txt3
$ diff -u txt txt3
$ diff -u txt txt3 | vi -
$ vi txt3
$ diff -u txt txt3 | vi -
$ vi txt3
$ diff -u txt txt3 | vi -
$ vi txt3
$ diff -u txt txt3 | vi -
$ vi -d txt txt3

Funções separadas em uma biblioteca

$ cds
$ vi functions
$ ./functions
$ source functions
$ . functions
$ vi inet
— EOF —

Gostou desse texto? Aqui tem mais.