Eu uso muito alias e funções no bash/zsh que facilita o dia a dia.
Estou criando este tópico para quem quiser compartilhar as suas alias
# Colorir páginas de manuais
export LESS_TERMCAP_mb=$(printf '\e[01;31m') # Entrar no modo intermitente - vermelho
export LESS_TERMCAP_md=$(printf '\e[01;35m') # Entrar no modo de duplo brilho - negrito, magenta
export LESS_TERMCAP_me=$(printf '\e[0m') # Desativar todos os modos de aparência (mb, md, so, us)
export LESS_TERMCAP_se=$(printf '\e[0m') # Deixar o modo standout
export LESS_TERMCAP_so=$(printf '\e[01;33m') # Entrar no modo standout - amarelo
export LESS_TERMCAP_ue=$(printf '\e[0m') # Deixar o modo sublinhado
export LESS_TERMCAP_us=$(printf '\e[04;36m') # Entrar no modo sublinhado - ciano
Para quem usa opensuse
# openSUSE
alias atualizar='sudo zypper dup'
alias remover='sudo zypper remove --clean-deps'
#alias remover='sudo zypper remove'
alias instalar='sudo zypper install'
alias procurar='zypper search --installed-only'
alias pesquisar='sudo zypper search'
alias orfaos='zypper pa --orphaned'
alias remove-orfaos='sudo zypper rm -u'
desnecessario(){
zypper packages --unneeded|awk -F '|' '{print $3}'| tail -n +5
}
# Listar arquivos de hoje
alias lshoje='ls -al --time-style=+%D | grep `date +%D`'
# Lista grupos
alias grupos='cut -d: -f1 /etc/group'
# otimizar pdf
alias otimizarpdf='ps2pdf -dPDFSETTINGS=/ebook'
# Mostrar permissão
alias permissão='stat -c "(%F)- %n %a %A" "$@"'
# Mostrar as montagens por coluna
alias cmount="mount | column -t"
# Mostrar portas abertas/ativas tcp e udp
alias portas='netstat -tulanp'
Funções
# Lista unidades do systemd
listar-arquivos-unit(){
[[ "$1" == "s" && "$#" -lt 2 ]] && systemctl list-unit-files;
[[ "$1" == "u" && "$#" -lt 2 ]] && systemctl list-unit-files --user;
[[ "$1" == "sm" && "$#" -lt 2 ]] && systemctl list-unit-files --state masked;
[[ "$1" == "um" && "$#" -lt 2 ]] && systemctl --user list-unit-files --state masked;
[[ "$1" == "se" && "$#" -lt 2 ]] && systemctl list-unit-files --state=enabled;
[[ "$1" == "sd" && "$#" -lt 2 ]] && systemctl list-unit-files --state=disabled;
[[ "$1" == "ss" && "$#" -lt 2 ]] && systemctl list-unit-files --state=static;
[[ "$1" == "ue" && "$#" -lt 2 ]] && systemctl --user list-unit-files --state=enabled;
[[ "$1" == "ud" && "$#" -lt 2 ]] && systemctl --user list-unit-files --state=disabled;
[[ "$1" == "us" && "$#" -lt 2 ]] && systemctl --user list-unit-files --state=static;
if [[ "$#" -eq 0 || "$1" != "s" && "$1" != "u" && "$1" != "sm" && "$1" != "um" && "$1" != "se" && "$1" != "sd" && "$1" != "ss" && "$1" != "u" && "$1" != "ue" && "$1" != "ud" && "$1" != "us" ]]; then
cat << USOAJUDA
$@ não é uma opção válida.
ajuda: listar-arquivos-unit [opções]
s : Mostra os arquivos unit do sistema
u : Mostra os arquivos unit do usuário
sm : Mostra os arquivos unit do sistema mascaradas
um : Mostra os arquivos unit do usuário mascaradas
se : Mostra os arquivos unit do sistema habilitados
sd : Mostra os arquivos unit do sistema desativados
ss : Mostra os arquivos unit do sistema estáticos
ue : Mostra os arquivos unit do usuário habilitados
ud : Mostra os arquivos unit do usuário desativados
us : Mostra os arquivos unit do usuário estáticos
USOAJUDA
fi
}
# Lista usuários
usuarios(){
[[ "$1" == "r" && "$#" -lt 2 ]] && awk -F : '$3 < 1 || $3 >= 1000 { print $1}' /etc/passwd;
[[ "$1" == "c" && "$#" -lt 2 ]] && awk -F : '$3 >= 1000 { print $1}' /etc/passwd;
[[ "$1" == "s" && "$#" -lt 2 ]] && awk -F : '$3 > 0 && $3 < 1000 { print $1}' /etc/passwd;
[[ "$1" == "S" && "$#" -lt 2 ]] && sudo pdbedit -L | cut -d \: -f1;
if [[ "$#" -eq 0 ]]; then
cut -d \: -f1 /etc/passwd;
elif [[ "$#" -gt 1 || "$1" != "c" && "$1" != "r" && "$1" != "s" && "$1" != "S" ]]; then
cat << USOAJUDA
$@ não é uma opção válida.
ajuda: usuarios [opções]
r : Mostra com o usuário root
c : Mostra usuários criados sem o serviços
s : Mostra usuários de serviços
S : Mostra usuários do samba
Exemplo:
usuarios r
usuarios
USOAJUDA
fi
}
# Históricos mais usados
maisusados(){
history | awk '{CMD[$2]++;count++;}END { for (a in CMD)print CMD[a] " " CMD[a]/count*100 "% " a;}' | grep -v "./" | column -c3 -s " " -t | sort -nr | nl | head -n10
}
# Color Console
if [ "$TERM" = "linux" ]; then
_SEDCMD='s/.*\*color\([0-9]\{1,\}\).*#\([0-9a-fA-F]\{6\}\).*/\1 \2/p'
for i in $(sed -n "$_SEDCMD" $HOME/.Xresources | awk '$1 < 16 {printf "\\e]P%X%s", $1, $2}'); do
echo -en "$i"
done
clear
fi
# Subir pastas
subir() {
local d=""
limit=$1
for ((i=1 ; i <= limit ; i++)); do
d=$d/..
done
d=$(echo $d | sed 's/^\///')
if [[ -z "$d" ]]; then
d=..
fi
cd $d
}
Olá @swatquest,
As suas função poderiam ser mais simples, para ajudar você e quem estiver começando com shell script, irei explicar:
É bem comum ver quem não tem muita experiência com scripting ou programação ficar repetindo métodos de checagem para executar uma ação. Entanto isto só é recomendado para casos muito complexos/específicos.
Exemplo:
Aqui você queira que múltiplas ações fossem executadas no caso de a variável $# ser menor que 2 e de a variável $1 for igual a uma string, você poderia ter feito de forma a utilizar apenas um if e um case, mostrarei em codigo:
if [ "$#" -lt 2 ]; then
case "$1" in
"r") awk -F : '$3 < 1 || $3 >= 1000 { print $1}' /etc/passwd;;
# Outras opções...
*) echo "Opção '$1' invalida.";;
esac
fi
Desta forma é muito melhor para ler e ainda mais logicamente falando, se você quer verificar as opções na condição de ter passado apenas um argumento é melhor verificar se $# é igual a 1.
Alterei algumas de suas funções para exemplo:
# Lista unidades do systemd
lsau(){
hmsg012391299TMP="\n'$@' não é uma opção válida.\n\nAjuda: listar-arquivos-unit [OPÇÂO]\n s : Mostra os arquivos unit do sistema\n u : Mostra os arquivos unit do usuário\n sm : Mostra os arquivos unit do sistema mascaradas\n um : Mostra os arquivos unit do usuário mascaradas\n se : Mostra os arquivos unit do sistema habilitados\n sd : Mostra os arquivos unit do sistema desativados\n ss : Mostra os arquivos unit do sistema estáticos\n ue : Mostra os arquivos unit do usuário habilitados\n ud : Mostra os arquivos unit do usuário desativados\n us : Mostra os arquivos unit do usuário estáticos\n"
if [ "$#" -eq 1 ]; then
case "$1" in
"s" ) systemctl list-unit-files;;
"u" ) systemctl list-unit-files --user;;
"sm" ) systemctl list-unit-files --state masked;;
"um" ) systemctl --user list-unit-files --state masked;;
"se" ) systemctl list-unit-files --state=enabled;;
"sd" ) systemctl list-unit-files --state=disabled;;
"ss" ) systemctl list-unit-files --state=static;;
"ue" ) systemctl --user list-unit-files --state=enabled;;
"ud" ) systemctl --user list-unit-files --state=disabled;;
"us" ) systemctl --user list-unit-files --state=static;;
*) echo -e $hmsg012391299TMP ;;
esac
else
echo -e $hmsg012391299TMP
fi
# Utilizei o unset para limpar a variável por que não há
# necessidade de ela existir depois que sair da função.
unset hmsg012391299TMP
}
# Lista usuários
usuarios(){
hmsg012391299TMP="'$@' não é uma opção válida.\n\nAjuda: usuarios [OPÇÂO]\n r : Mostra com o usuário root\n c : Mostra usuários criados sem o serviços\n s : Mostra usuários de serviços\n S : Mostra usuários do samba\n\n Exemplo:\n\n usuarios r\n usuarios"
if [ "$#" -eq 0 ]; then
cut -d \: -f1 /etc/passwd
elif [ "$#" -eq 1 ]; then
case "$1" in
"r") awk -F : '$3 < 1 || $3 >= 1000 { print $1}' /etc/passwd;;
"c") awk -F : '$3 >= 1000 { print $1}' /etc/passwd;;
"s") awk -F : '$3 > 0 && $3 < 1000 { print $1}' /etc/passwd;;
"S") sudo pdbedit -L | cut -d \: -f1;;
* ) echo -e $hmsg012391299TMP;;
esac
else
echo -e $hmsg012391299TMP
fi
unset hmsg012391299TMP
}
Uma outra opção em vez do unset: quando tenho funções com variáveis que posso descartar imediatamente, eu utilizo a sintaxe funcao() ( comando1; comando2; ) que é inclusive prevista na POSIX (suportada também por shells mais simples como dash, mksh, etc.). Ela roda o código da função num shell paralelo, sem mexer no que está rodando atualmente.
cppwr() ( # em vez de {
# ...
GOV=$(LC_ALL=C cpupower frequency-info -p | grep -o '"[a-z]\+"' | tr -d '"') # Essa variável está sendo definida num "shell paralelo", não vai afetar o shell principal
#...
) # em vez de }
Outra opção é usar local variavel no começo da função, para o shell entender que a variável é específica daquele bloco (alguns shells mais minimalistas não sabem mexer com isso, no entanto):
lsau() {
local hmsg="\n '$@'" #...
#...
}
ou
lsau() {
local hmsg
hmsg="Ajuda:"
#...
}
Nem é necessário o monte de dígitos para não confundir acidentalmente com outra variável que o usuário/outra função talvez já esteja usando.
no KDE, que é a DE que eu uso, eu adiciono um atalho pra desligar e reiniciar o computador
CTRL + META + SHIFT + R pra reiniciar e CTRL + META + SHIFT + P pra desligar
a única alias que eu tenho no meu .bashrc é o update
O script primeiro verifica se é possível fazer um AppImage, se sim, ele gera, se não verifica se é um snap, por fim se não for possível gerar um AppImage através do pkg2appimage, nem for um snap, ele tenta instalar usando o APT
function app-install() {
local pasta_trabalho=$(mktemp -d)
local debs=()
cd ${pasta_trabalho}
mkdir -p ${HOME}/.local/bin
mkdir -p out
for arg in ${@}; do
wget -q --method=HEAD "https://raw.githubusercontent.com/AppImage/pkg2appimage/master/recipes/${arg}.yml" && {
echo "${arg} vai ser um AppImage"
pkg2appimage "${arg}"
} || {
wget -q --method=HEAD "https://snapcraft.io/${arg}" && {
echo "${arg} vai ser um Snap"
sudo snap install "${arg}"
} || {
echo "${arg} vai ser instalado usando o APT"
debs+=(${arg})
}
}
done
[ ! "${#debs[@]}" = "0" ] && {
sudo apt install ${debs[@]} --no-install-recommends
}
mv ./out/* $HOME/.local/bin
cd ~
rm -rf ${pasta_trabalho}
}
Ressuscitando esse tópico com alguns scripts que eu fiz (em spoilers porque são longos):
YouTube DL + Corte com base na descrição do vídeo
#! /bin/bash -ex
# Usei bash -ex no #!, melhor criar a pasta pra não ter erro
mkdir -p ~/.cache/youtube-multi-dl
# Conservar o cache se o download tiver sido pulado.
if [[ ! " $* " =~ " --skip-download " ]]; then rm -rf ~/.cache/youtube-multi-dl; fi
# Cria de novo pra garantir.
mkdir -p ~/.cache/youtube-multi-dl
# Baixar o vídeo e todas informações aí e Enviar o vídeo como link simbólico
# para a pasta de cache criada lá em cima.
# Foi a melhor maneira que eu achei para garantir que a extensão ia ser
# detectada corretamente na hora de cortar o vídeo.
youtube-dl "$@" --write-info-json --exec 'ln -s "$PWD"/{} ~/.cache/youtube-multi-dl'
# Função para cortar o vídeo
_cut() {
# Checar se o arquivo existe para não esbarrar no -ex.
if [ ! -f "$4" ]; then
ffmpeg -nostdin \
-loglevel 8 \
-i "$1" \
-c copy \
-ss `[ -n "$2" ] && echo "$2" || echo 0` \
`[ -n "$3" ] && echo -to "$3"` \
-- "$4"
else
echo "$4" já existe.
fi
}
# Se não tiver nada no cache, só pula o for.
shopt -s nullglob
for OUTFILE in ~/.cache/youtube-multi-dl/*; do
# Pegar o caminho ao qual o link simbólico faz referência.
FILENAME=$(realpath "$OUTFILE")
# Pegar o Json com informações (inclusive os cortes).
INFOFILE=${FILENAME%.*}.info.json
# Pegar a extensão do arquivo.
EXT=${FILENAME##*.}
i=0
# Loopar nos cortes até não ter mais capítulos para cortar.
while [ ! "`jq ".chapters[${i}]" "$INFOFILE"`" = null ]; do
readarray -t INFO < <(jq -r ".chapters[${i}].title,.chapters[${i}].start_time,.chapters[${i}].end_time" -- "$INFOFILE")
_cut "$FILENAME" "${INFO[1]}" "${INFO[2]}" "${INFO[0]}"."$EXT"
i=$((i+1))
done
# Se tiver um comentário com as timestamps, cola na pasta de saída como
# um arquivo de texto chamado CUTS sem extensão. O script se vira para
# cortar o arquivo.
if [ -f CUTS ]; then
TIME_PAT='[0-9]+(:[0-5]?[0-9]){1,2}' # HH:MM:SS em regex
sA= #começo de um corte.
sB= # final de um corte.
sOLDOUT= #Nome do título anterior. Caso haja apenas uma timestamp por
# lina.
# Essas três variáveis vão fazer sentido no ELSE.
while read -r LINE; do
# Tirar tudo quanto é timestamp, depois espaço e pontuação no come-
# ço para achar o título do corte.
read -r TITLE < <(sed -r "s/.*(${TIME_PAT})//g" <<<$LINE | sed -r 's/^([[:punct:]]|[[:space:]])+//g')
# Achar as timestamps pelo Regex.
readarray -t TIMES < <(grep -Eo "$TIME_PAT" <<<$LINE)
if [ -n "${TIMES[0]}" ] && [ -n "${TIMES[1]}" ]; then
# Achou duas timestamps (começo e fim, nessa ordem)
_cut "$FILENAME" "${TIMES[0]}" "${TIMES[1]}" "$TITLE"."$EXT"
# Para caso ele fique alternado entre começo e fim e só começo
# de timestamp
sA=${TIMES[1]}
sOLDOUT="`uuidgen`"."$EXT"
elif [ -z "${TIMES[0]}" ] && [ -z "${TIMES[1]}" ]; then
# Zero timestamps nessa linha. Só pula.
continue
else
# Só uma timestamp por linha. Significa que entre as time-
# stamps há um corte.
# Timestamp atual - final de um corte.
sB=$TIMES
if [ -z "$sA" ]; then
: # Opa. A gente nem tinha começado a cortar.
else
# Corte que foi anunciado linha passada.
_cut "$FILENAME" "$sA" "$sB" "$sOLDOUT"
fi
# O final de um, o começo de outro.
sA=$sB
# Pegar o título do corte que começa agora.
sOLDOUT="$TITLE"."$EXT"
fi
done < CUTS
if [ -n "$sOLDOUT" ]; then # Caso haja um corte sobrando...
# Corta a partir do último começo de corte registrado.
_cut "$FILENAME" "$sA" "" "$sOLDOUT"
fi
fi
done
Requer youtube-dl e jq.
Fiz o possível para o --help do Youtube-DL se aplicar a ele.
Remover anotações de PDF
#! /bin/sh -ex
# https://gist.github.com/stefanschmidt/5248592
test -f "$1"
OUT=$2
if [ -z "$OUT" ]; then
OUT=$(basename "$1")
while [ -f "$OUT" ]; do
OUT="${OUT%.pdf}".un.pdf
done
fi
pdftk "$1" output - uncompress | LANG=C LC_CTYPE=C sed -n '/^\/Annots/!p' | pdftk - output "$OUT" compress
#!/bin/bash -e
# http://www.alfredklomp.com/programming/shrinkpdf
cleanup() {
if [ -d "$WORKDIR" ]; then
rm -r "$WORKDIR"
fi
}
DPI=$3
[ -z "$DPI" ] && DPI=72
OUT=$2
[ -z "$OUT" ] && OUT=-
GS_OPTS="
-q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite
-dAutoRotatePages=/None
-dColorImageDownsampleType=/Bicubic
-dColorImageResolution=$DPI
-dGrayImageDownsampleType=/Bicubic
-dGrayImageResolution=$DPI
-dMonoImageDownsampleType=/Subsample
-dMonoImageResolution=$DPI
"
WORKDIR="$(dirname "$1")"/.tmp"$(tr -d '[[:space:]]' <<<$1)"
mkdir -p "$WORKDIR"
trap INT TERM EXIT cleanup
gs -o "$WORKDIR"/bg.pdf $GS_OPTS -dFILTERTEXT -dPDFSETTINGS=/screen "$1" &
gs -o "$WORKDIR"/input.pdf $GS_OPTS -dFILTERIMAGE -dFILTERVECTOR "$1"
wait # wait for all jobs to finish...
pdftk "$WORKDIR"/input.pdf multibackground "$WORKDIR"/bg.pdf output "$OUT"
Requer ghostscript e pdftk.
Uso pdfcompress entrada.pdf saida.pdf RESOLUÇÃO
Resolução é em pontos por polegada (padrão: 72).
Conversor de imagens e documentos
#! /bin/sh
if test -z "$1"; then
echo 'Comece com um nome de arquivo ou extensão'
exit 1
fi
# $1 é um arquivo, pdf logo
if test -f "$1"; then
OUTF=pdf
fi
for arg; do
if test -z "$arg"; then
echo 'Argumento vazio!'
exit 1
fi
if ! test -f "$arg"; then
# Não é um arquivo, é uma extensão de arquivo
OUTF=$1
continue
fi
MIME=`file --brief --mime-type "$arg"`
M=`echo $MIME | cut -d/ -f1`
CONVCMD=
if [ "$M" = image -o "$M" = video -o "$MIME" = application/pdf ]; then
CONVCMD='mogrify -format'
elif [ "$M" = application -o "$M" = text ]; then
CONVCMD='libreoffice --headless --convert-to'
else
echo 'O arquivo' "$arg" 'parece não ser suportado.'
exit 1
fi
($CONVCMD $OUTF "$arg" && echo Arquivo "$arg" convertido para "${arg%.*}.${OUTF}". || echo Conversão de "$arg" falhou.) &
done
wait
Requer o LibreOffice e o ImageMagick.
Uso: conv FORMATO1 ARQUIVO(S) FORMATO2 ARQUIVO(S)
Agora que estou vendo o quanto eu usei arquivos PDF em 2020.
Vi esse script num vídeo do YouTube (já dizendo que não é bem ideia minha), mas ele é muito bom e gostaria de compartilhar aqui. É um seletor de emoji simples, baseado no rofi/dmenu (programas leves que iniciam rápido, diferente de um certo programa cof cof seletor de emoji do KDE cof cof)
Requisitos são rofi (ou dmenu) e xclip, e um arquivo com uma lista de emojis (um por linha).
Gerando a tal lista de emoji
A maneira mais direta de fazer um arquivo com todos os emojis do mundo, um por linha, é ir direto na fonte, o Unicode Consortion:
# Pegar a lista oficial de emojis
wget -q 'https://unicode.org/Public/emoji/13.1/emoji-test.txt' -O - |
# Pegar apenas emojis completos
grep '; fully-qualified' |
# Filtrar informações irrelevantes (código, versão que apareceu, etc.) - deixar só nome e emoji em si
cut -d'#' -f2 | cut -d' ' -f2,4- \
> ~/.config/emoji.list # Soltar a saída para um arquivo, com a lista de emojis.
Conteúdo do arquivo de script em si - versão rofi
#! /bin/sh
# Variável com o emoji.
EMOJI=$(
# Ler o arquivo ~/.config/emoji.list e pedir para o usuário escolher um.
<~/.config/emoji.list rofi -dmenu -i -sync -p 'Emoji' |
cut -d' ' -f1 # Cortar a descrição.
)
# Emoji selecionado, não vazio:
if [ -n "$EMOJI" ]; then
# Passar para área de transferência
echo "$EMOJI" | xclip
# Notificar
notify-send "$EMOJI foi copiado para área de transferência." -a 'Seletor de emoji'
fi
Conteúdo do arquivo de script em si - versão dmenu
#! /bin/sh
# Variável com o emoji.
EMOJI=$(
# Ler o arquivo ~/.config/emoji.list e pedir para o usuário escolher um.
<~/.config/emoji.list dmenu -i -l 20 |
cut -d' ' -f1 # Cortar a descrição.
)
# Emoji selecionado, não vazio:
if [ -n "$EMOJI" ]; then
# Passar para área de transferência
echo "$EMOJI" | xclip
# Notificar
notify-send "$EMOJI foi copiado para área de transferência." -a 'Seletor de emoji'
fi
Jogos mais antigos que rodam via Wine no X11 têm o péssimo hábito de mudar a resolução de tela (geralmente para 800x600, 1024x768 e outras 4:3) e nem sempre colocar adequadamente de volta a resolução antiga. Esse é um problema bem comum pra mim, então esse script me permite só digitar corrige_wine_burro.sh no terminal e voltar para a resolução normal.
#!/bin/sh
xrandr -q | while read -r disp state _
do
# ignorar monitores desconectados
[ "$state" = connected ] || continue
read -r mode _
# essa linha serve para ignorar 1920x1080 e resoluções maiores na minha TV.
# comente as 3 linhas seguintes se você tem monitor 1080p/4K
while [ "${mode#*x}" -ge 1080 ]; do
read -r mode _
done
# redefinir resolução
xrandr --output "$disp" --mode "$mode" &&
printf ':: %s - agora %s\n' "$disp" "$mode"
done
Eu faço uso às vezes também, mas tenho bem poucas, alguns são só 4fun, então minha humilde contribuição é:
Alias for remove with prompt
alias rm=‘rm -i’
Alias for Screencopy
alias android=‘scrcpy -w --window-borderless’
Alias for sudo
alias please=‘sudo’
Alias for IP
alias ip=“hostname -I”
Alias for Atualização
alias up=“sudo apt update && sudo apt dist-upgrade”
Extra
Também tem esse aqui, que uso pouco mas é bacana para comandos que vão levar um certo tempo, como compilar alguma coisa, ou fazer download de alguma, etc.