SHELL wget Download de Arquivo via Linha de Comando

# baixar com o nome padrão phpunit-9.phar
wget https://phar.phpunit.de/phpunit-9.phar

# baixar e renomear para o nome phpunit
wget -O phpunit https://phar.phpunit.de/phpunit-9.phar

# qualquer endereço http pode ser o alvo para download
wget -O my-project https://mega.nz/file/<mega-nz-download-hash-with-password-embedded>

Parece básico, mas fazer o download de arquivos da internet sem usar um navegador pode ser uma tarefa árdua e desconhecida para a maioria dos usuários da internet.

Porém para desenvolvedores web, engenheiros de software e profissionais de tecnologia da informação dominar essa habilidade deve ser primordial.

O pacote wget é extremamente simples e versátil, pelo menos o seu uso básico não apresenta nenhuma dificuldade como podemos evidenciar acima. Para ambientes Linux ele já vem previamente instalado, ou se necessário pode ser facilmente instalado pelos gerenciadores de pacote.

sudo apt install wget -y      [On Debian, Ubuntu and Mint]
sudo yum install wget -y      [On RHEL/CentOS/Fedora]
sudo emerge -a net-misc/wget  [On Gentoo Linux]
sudo pacman -Sy wget          [On Arch Linux]
sudo zypper install wget      [On OpenSUSE] 

Para usuários MacOS o recurso pode ser instalado pelo gerenciador de pacotes brew.

brew install wget

Ou então, se o seu caso de uso é realmente básico você pode optar pelo uso do CURL, que vai funcionar mesmo no OSX nativamente.

# baixar com o nome padrão phpunit-9.phar
curl -O https://phar.phpunit.de/phpunit-9.phar

# baixar e renomear para o nome phpunit
curl https://phar.phpunit.de/phpunit-9.phar -o phpunit

O wget possui muitas outras funcionalidades mais avançadas, mas a ideia aqui é demonstrar o caso de uso simples mesmo.

Agora você já sabe, baixaki nunca mais!

SHELL Copiando e Colando no Terminal com pbcopy e pbpaste

# copiar conteúdo do arquivo para a memória clipboard
cat linefeed.sql | pbcopy

# colar conteúdo da memória clipboard no terminal
pbpaste

Para quem usa a interface SHELL é bastante corriqueiro tratar e sanitizar dados utilizando uma sequência de comandos e no final ecoar o resultado no próprio terminal.

Mas e daí? Como fazer para transferir estes dados para outro aplicativo?

O mais usual é selecionar os dados como próprio mouse no terminal caracter e pressionar Ctrl+C e posteriormente Ctrl+V no aplicativo destino.

Mas essa operação pode ser cansativa ou mesmo inviável quando estamos falando de um grande volume de dados.

Mas so seus problemas acabaram, agora com pbcopy e pbpaste você não vai mais cometer erros.

Só que estes comandos são originários do mundo OSX. Quem usa ambiente Linux precisa usar o comando xsel ou então simular os comandos Mac via alias.

alias pbcopy=’xsel — clipboard — input’
alias pbpaste=’xsel — clipboard — output’

Pronto, agora você pode usar os mesmos comandos do Mac no seu ambiente Linux.

A propósito, depois de muito pesquisar entendi que o prefixo pb remete a Pasteboard Buffer. É o mesmo que conhecemos no mundo Windows por Clipboard.

Fez sentido agora? Pra mim também…

Stream Editor sed Substituir texto \n por Quebra de Linha via Linha de Comando

#linux
sed -i 's/\\n/\n/g' linefeed.sql

#macOS
sed -i '' 's/\\n/\n/g' linefeed.sql

Hoje novamente me deparei com um bloco de texto de linha única, ou seja as quebras de linha foram geradas como string texto \n e não como o caracter linefeed ou carriage return como eu esperava.

Bom, não importa, isso acontece eventualmente então fazer a substituição manual via comando sed é a forma mais rápida de alcançar este objetivo.

Explicando rapidamente o comandos acima…

sed é o acrônimo para Stream Editor

-i significa in place, ou seja, vai alterar o próprio arquivo de entrada

's/\\n/\n/g' é um regex pattern, s para substituir, \\n conteúdo a ser substituído, \n conteúdo a ser aplicado, g troca global ou múltiplas ocorrências.

As barras / funcionam apenas como delimitadores do regex pattern.

linefeed.txt é o nome do arquivo de entrada, ou seja o nosso arquivo alvo 

Observe que no ambiente MacOS temos uma ligeira diferença onde um parâmetro adicional surge antes do regex pattern. Deu muiiiiiiito trabalho pra descobrir isso!

Criando o arquivo com o conteúdo necessário para simular o problema.

echo 'CREATE TABLE usuario (\\n id BIGINT(20) NOT NULL AUTO_INCREMENT,\\n nome VARCHAR(255) NOT NULL,\\n login VARCHAR(50) NOT NULL,\\n email VARCHAR(255) NOT NULL,\\n senha VARCHAR(50) NOT NULL,\\n telefone_fixo VARCHAR(50) DEFAULT NULL,\\n telefone_celular VARCHAR(50) DEFAULT NULL,\\n timezone VARCHAR(100) DEFAULT NULL,\\n ativo TINYINT(3) UNSIGNED NOT NULL,\\n created_at DATETIME(6) DEFAULT CURRENT_TIMESTAMP(6),\\n updated_at DATETIME(6) DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),\\n PRIMARY KEY (id),\\n UNIQUE KEY ixu_login (login),\\n KEY idx_usuario_created_at (created_at),\\n KEY idx_usuario_updated_at (updated_at)\\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;' > linefeed.sql

Listando e conferindo que temos apenas uma única linha no arquivo.

cat linefeed.sql

Para os amantes do editor vi podemos fazer essa mesma substituição com a seguinte sequência de comandos.

vi linefeed.sql
:1,$ s/\\n/\r/g <enter>
:wq

Observe que neste comando o conteúdo a ser aplicado deve ser \r e não \n

É claro que você poderia se livrar de toda essa parafernália de comandos e simplesmente utilizar um editor de textos que tenha um suporte esperto, como Notepad++ ou VsCode, e simplesmente Localizar e Substituir strings por LF CR.

Mas fica aqui a minha pergunta. Por que você iria querer isto?

Thanks for watching!!!

Linux Type e Which Para Localizar Path de Comandos e Executáveis

type -a bash
type -a zsh
type -a git
type -a asdf

which bash
which zsh
which git

Olha só que legal! Em algumas situações precisamos descobri o PATH de alguns comandos, pacotes ou programas instalados no seu sistema operacional.

Antigamente eu costumava fazer isso com o locate ou find, mas o resultado nem sempre era fácil de obter com estes dois recursos.

Recentemente eu estava configurando vários pacotes no meu Arch Linux Desktop e tive que encontrar o path de um aplicativo para poder configurar corretamente. Foi aí que me deparei com estes dois recursos mais modernos e mais fáceis de usar.

O type funcionou perfeitamente com os vários pacotes incluindo o asdf. Já o which falhou com o asdf não sei exatamente o porquê.

Na dúvida, vai de type… mas o which também manda bem pra caramba!

SHELL Bash Remover Arquivos Selecionados com Find -exec

find folder -type f -name '*.txt' -exec rm {} +

Para quem tem de lidar com arquivos físicos em sua rotina diária eu tenho certeza de que em algum momento já precisou fazer um eliminação de determinados arquivos, arquivos estes misturados com outros milhares de arquivos, e ainda espalhados por diversos subdiretórios que você nem sequer pudesse imaginar onde estariam.

Bom, não é mais a minha rotina, mas um dia já precisei fazer este tipo de limpeza antes de entregar um deploy; Eu precisei limpar arquivos que não faziam parte do codebase do sistema, arquivos tipo teste e upload… daí bateu aquele frio na espinha!

Dei bastante sorte, numa rápida pesquisa um desses caras legais que ficam escrevendo dicas na internet escreveu um artigo que resolvia exatamente o meu problema. Então, explicando o comando acima:

O comando find vai buscar no diretório folder todos os elementos do tipo arquivo -type f cujo nome faça match com a extensão texto -name ‘*.txt’ e mais que isso, a busca na verdade vai ser processada de forma recursiva descendo até o último nível de diretório existente, já que um nível máximo -maxdepth não foi estipulado.

A remoção dos arquivos encontrados é processada com a opção de executar -exec um comando shell rm para remoção. O sinal de mais + ao final do comando é uma exigência da sintaxe para esta construção.

A mágica na verdade acontece nos brackets {} onde o mesmo é substituído por todas as ocorrências encontradas pelo comando find.

Pronto, sua remoção foi processada de forma limpa e segura!

Você poderia abusar ainda mais das opções de busca, no caso poderia informar as negativas, ou seja, apenas o conjunto de arquivos que não deseja remover.

find folder -type f '!' -name '*.css' '!' -name '*.js' '!' -name '*.php' -exec rm {} +

Segue abaixo uma sketch para montar um ambiente de testes para exercitar os comandos e poder remover os arquivos com segurança.

mkdir folder
mkdir folder/bkp

touch folder/one.txt
touch folder/two.txt
touch folder/three.csv
touch folder/four.txt

cp folder/*.* folder/bkp
touch folder/bkp/six.txt 

Aqui os comandos sem a remoção para você entender o comando find um pouco melhor. Tente variar as combinações de busca para ver o comportamento.

find folder -type f -name '*.txt'

find folder -type f '!' -name '*.css' '!' -name '*.js' '!' -name '*.php'

Agora você já sabe, ao invés de tentar aquele comando cujo nome não pode ser pronunciado (rm -r), agora você conhece uma opção muito mais segura. Se não for usá-la, é por sua conta e risco!

GIT Rebase com Git Pull durante atualização da Branch

git pull --rebase origin master --autostash

Quem se lembra de quando começou a trabalhar com GIT e tinha medo de fazer um rebase e melar a branch atual?

Pois é, o rebase na verdade é uma ação muito tranquila de ser executada, ainda mais se utilizarmos como opção de outro comando amplamente conhecido e dominado por todos.

Isso mesmo, fazer o rebase durante a atualização da branch é possível, e sinceramente, depois de ter aprendido esta forma não me recordo de ter utilizado o git rebase isoldamente.

Explicando o comando acima, fazer um git pull é super tranquilo certo? Você faz o pull quando precisa trazer as atualizações do servidor para a sua branch local, ponto. Mas o que acontece se você ja tem um commit nesta sua branch local?

Isso mesmo, para que o seu commit fique no topo da pilha você precisa fazer um rebase. Assim o Git gentilmente lhe dá a opção de fazer o rebase no mesmo momento de atualizar a branch.

A opção –autostash ajuda quando você possuir alterações ainda sem commit, assim você economiza mais um tanto e não precisa fazer o stash manual antes de atualizar a branch.

Mágico, não?

GIT Configurando comportamento padrão para Git Status e Git Push na linha de comando

git config --global status.showuntrackedfiles all
git config --global push.default current

Operar o Git através de ferramentas gráficas é muito fácil, mas este não é o ambiente nativo disponibilizado pela ferramenta.

Saber operar o Git pela linha de comando é o máximo, mas leva algum até você conseguir dominar a sintaxe e memorizar os principais comandos. Além disso, o ambiente pode ser configurado para se comportar adotando alguns padrões pré-estabelecidos que são muito usuais, assim você acaba economizando na digitação e também nos erros.

Os comandos acima são dois padrões que eu costumo configurar logo após instalar o Git.

A primeira configuração faz com que o comando git status mostre os arquivos novos criados que ainda não foram adicionados ao repositório. Sem este default configurado seria necessário informar um argumento opcional –untracked-files para visualizar os arquivos novos. Os comandos abaixo irão listar todos os arquivos novos.

git status -u
git status -uall
git status --untracked-files
git status --untracked-files=all

A segunda configuração faz com que o comando git push envie os commits para o servidor remoto atualizando a branch com o mesmo nome da branch local. Sem este default configurado seria necessário informar adicionalmente o local do repositório e o nome da branch remota. Os comandos abaixo representam a forma de fazer o push dos commits para a branch desejada, neste exemplo enviando para a mesma branch localmente posicionada.

git checkout master
git commit -m "commit your changes"
git push origin master

git checkout -b first-branch
git commit -m "commit your changes"
git push origin first-branch

Lembrando que você pode a qualquer momento verificar as configurações correntemente válidas para o seu ambiente ou ainda remover alguma configuração indesejada.

git config --list
git config --unset status.showuntrackedfiles 

Obviamente existem muitas outras personalizações que podem ser configuradas, mas estas duas eu considero essenciais para a operação do dia a dia.