Disinteressato

Un Terminale è per sempre (e altre cosette)

Quando a metà anni 2000 iniziai ad usare un Mac il terminale proprio non me lo filavo.

In quell’era geologica c’era ancora la sbornia evolutiva portata dall’aumento esponenziale e costante della potenza dei processori con interfacce sempre più belle e ricche di funzionalità, quindi fare un passo indietro ed usare il terminale non era contemplato. E poi venivo da Windows e il Prompt dei comandi neanche sapevo cosa fosse.

Col tempo ho apprezzato l’uso che se ne può fare, come possa essere effettivamente più rapido per alcune operazioni, inutilmente complesso per altre, ma soprattutto che è l’ultima ancora di salvezza per uscire dai guai nei sistemi Unix.

Ritenendomi adesso un utente discretamente esperto, almeno nel riconoscere le mie necessità, il mio approccio in questo nuovo viaggio con macOS è stato questo: cerco tutto il software che mi serve nell’App Store, se non lo trovo la scarico dai rispettivi siti ufficiali e verifico che ci sia la possibilità di ricercare gli aggiornamenti all’interno dell’applicazione stessa.

Queste sono le applicazioni che ho installato esternamente all’App Store:

Ho lasciato alla riga di comando le operazioni che possono essere svolte esclusivamente da terminale oppure quelle per le quali mi sento più a mio agio ad utilizzarlo.

Con macOS la prima cosa da fare è installare Homebrew, un gestore di pacchetti col quale scaricare, installare e mantenere aggiornato del software rigorosamente open source: in pratica è una specie di App Store da linea di comando. Anche l’installazione, ovviamente, avviene da riga di comando:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
uname -m | grep arm64 && echo 'export PATH=$PATH:/opt/homebrew/bin' >> ~/.zshrc && source ~/.zshrc

Piccolo extra, disattivare il monitoraggio di Homebrew Analytics:

brew analytics off

Invece, per aggiornare i pacchetti installati basteranno poi i seguenti comandi:

brew update
brew outdated
brew upgrade

Utilizzo pochi pacchetti perché quello di cui necessito è residuale o al massimo serve per estendere o completare alcune funzioni di macOS.

Quick Look

Per estendere le funzionalità di Quick Look ho installato questi plugin:

brew install --cask qlmarkdown qlvideo quicklook-csv

LaTeX

Per installare MacTex utilizzo Homebrew perché mi permette di non installare le applicazioni con interfaccia grafica, dato che andrò ad utilizzare LaTeX Workshop e Virtual Studio Code:

brew install --cask mactex-no-gui

Per aggiornare i pacchetti basterà utilizzare Tex Live Manager:

sudo tlmgr update --self && sudo tlmgr update --all

Caratteri

Ho installato solo i caratteri Roboto e Bebas Neue:

brew tap homebrew/cask-fonts
brew install svn
sudo mkdir -p /Library/Java/Extensions
sudo ln -s /opt/homebrew/lib/libsvnjavahl-1.dylib /Library/Java/Extensions/libsvnjavahl-1.dylib
brew install --cask font-roboto font-roboto-mono font-roboto-slab font-bebas-neue

nano

Per modificare da terminale i file di testo nano rimane insuperabile:

brew install nano nanorc
nano ~/.nanorc

# Non-default settings
set atblanks
set cutfromcursor
set nohelp
set softwrap
set tabsize         4
set tabstospaces
set constantshow
set linenumbers
set numbercolor     grey
set stateflags
set casesensitive
set historylog
set positionlog
set zap
set autoindent
set minibar
set minicolor       grey
set promptcolor     magenta
set selectedcolor   black,yellow
set spotlightcolor  bold,black,red
set mouse
set nonewlines
set saveonexit
set locking
set boldtext

# Shortcut key bindings
bind ^c copy main
bind ^v paste all
bind ^f whereis all
bind ^s savefile main
bind ^z undo main
bind ^y redo main
bind ^q exit main

# Add colour syntax
include "/opt/homebrew/Cellar/nano/*/share/nano/*.nanorc"

rsync

Sempre utile avere rsync per sincronizzare file o cartelle:

brew install rsync

yt-dlp

Per scaricare i video da YouTube utilizzo yt-dlp:

brew install yt-dlp/taps/yt-dlp
brew install atomicparsley ffmpeg

Questo invece è il mio file di configurazione:

$ nano ~/.config/yt-dlp/config

--no-mtime
--embed-metadata
--embed-thumbnail
# --write-thumbnail
--yes-playlist
-o /Users/simo/Downloads/YouTube/%(title)s.%(ext)s
-f 'bv*[ext=mp4]+ba[ext=m4a]/b[ext=mp4] / bv*+ba/b'
# -f 'ba[ext=m4a]/b[ext=mp4]'

ImageMagick

ImageMagick per la manipolazione delle immagini:

brew install imagemagick

ExifTool

ExifTool mi ha tolto dagli impicci di dover inserire i metadati (nello specifico: data e ora) alle circa 1700 foto scattate dal fotografo al mio matrimonio:

brew install exiftool

Fortunatamente i file erano stati nominati in ordine cronologico crescente di scatto, quindi mi è bastato dapprima inserire in tutte le foto la stessa data e la stessa ora (DIR è il nome della cartella che contiene i file):

exiftool -AllDates="YYYY:MM:DD HH:MM:SS" DIR -overwrite_original -r

Dopodiché ad ogni foto, in base all’ordine crescente di nome, sono stati aggiunti 10 secondi all’ora di scatto rispetto a quella della precedente, il tutto con questo unico comando:

exiftool '-AllDates+<0:0:${filesequence}0' DIR -fileOrder FileName -overwrite_original -r

Per verificare che la modifica sia stata effettuata correttamente, questo comando genera un file CSV facilmente analizzabile:

exiftool -AllDates -csv DIR > out.csv

In questo modo, una volta aggiunte alla libreria di Foto, erano in perfetto ordine cronologico (ovviamente l’ora di scatto era arbitraria e non rispettava quella effettiva, ma di meglio non si poteva fare).

Wget, tree e trash

Installo anche il classico Wget, Tree per visualizzare le cartelle in una struttura ad albero e Trash per spostare i file nel cestino da terminale evitando di poter solo cancellarli definitivamente usando il comando rm:

brew install wget trash tree

ZSH

Ed infine, visto che macOS utilizza ZSH come shell di default, perché non personalizzarla un pochino?

$ brew install pure zsh-autosuggestions
$ cd ~
$ touch ~/.hushlogin
$ nano ~/.zshrc

#!/usr/bin/env zsh

###############################
# EXPORT ENVIRONMENT VARIABLE #
###############################

# editor
export EDITOR='nano'
export VISUAL='nano'

# zsh
export HISTSIZE=10000                   # Maximum events for internal history
export SAVEHIST=10000                   # Maximum events in history file

# gpg needs this
export GPG_TTY=$(tty)


#############
# FUNCTIONS #
#############

# create a folder and move into it in one command
function mkcd() { mkdir -p "$@" && cd "$_"; }


###########
# HISTORY #
###########

setopt EXTENDED_HISTORY          # Write the history file in the ':start:elapsed;command' format
setopt SHARE_HISTORY             # Share history between all sessions
setopt HIST_EXPIRE_DUPS_FIRST    # Expire a duplicate event first when trimming history
setopt HIST_IGNORE_DUPS          # Do not record an event that was just recorded again
setopt HIST_IGNORE_ALL_DUPS      # Delete an old recorded event if a new event is a duplicate
setopt HIST_FIND_NO_DUPS         # Do not display a previously found event
setopt HIST_IGNORE_SPACE         # Do not record an event starting with a space
setopt HIST_SAVE_NO_DUPS         # Do not write a duplicate event to the history file
setopt HIST_VERIFY               # Do not execute immediately upon history expansion


##############
# NAVIGATION #
##############

setopt AUTO_CD              # Go to folder path without using cd
setopt AUTO_PUSHD           # Push the old directory onto the stack on cd
setopt PUSHD_IGNORE_DUPS    # Do not store duplicates in the stack
setopt PUSHD_SILENT         # Do not print the directory stack after pushd or popd
setopt CDABLE_VARS          # Change directory to a path stored in a variable
setopt EXTENDED_GLOB        # Use extended globbing syntax
setopt NO_LIST_AMBIGUOUS # Case insensivity


##########
# COLORS #
##########

export CLICOLOR=1
export LSCOLORS=ExFxBxDxCxegedabagacad


###########
# ALIASES #
###########

# system
alias brewup='brew update && brew upgrade && brew update --cask && brew upgrade --cask $(brew outdated) --cask && brew cleanup && brew autoremove && brew doctor'
alias texup='sudo tlmgr update --self && sudo tlmgr update --all'
alias myip='curl http://ipecho.net/plain; echo'

# folders
alias icloud='$HOME/Library/Mobile\ Documents/com~apple~CloudDocs/'
alias dot='$HOME/.dotfiles'

# cp
alias cp='cp -iv'
alias mv='mv -iv'
alias rm='echo "This is not the command you are looking for. Use trash instead."; false'
alias rcp='rsync -v --progress'
alias rmv='rsync -v --progress --remove-source-files'

# grep
alias grep='grep --color=auto'
alias fgrep='fgrep --color=auto'
alias egrep='egrep --color=auto'

# directory stack
alias d='dirs -v'
for index ({1..9}) alias "$index"="cd +${index}"; unset index

# history
alias hs='history | grep'

# commands
alias mkcd='foo(){ mkdir -p "$1"; cd "$1" }; foo '

# applications
alias edit='nano'


#####################
# COMPLETION SYSTEM #
#####################

# command completion
autoload -Uz compinit
compinit
# with hidden files
_comp_options+=(globdots)

# autocompletion with an arrow-key driven interface. To activate the menu, press Tab twice.
zstyle ':completion:*' menu select

# case insensitive path-completion
zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}'

# enables the auto-complete menu automatically selects the first item (yes) only for ls
zstyle ':completion:ls:*' menu yes select

# sets the auto-completion colors
zstyle ':completion:*:default' list-colors \
    'di=34:ln=35:so=32:pi=33:ex=31:bd=34;46:cd=34;43:su=30;41:sg=30;46:tw=30;42:ow=30;43'


##################
# HISTORY SEARCH #
##################

autoload -Uz up-line-or-beginning-search down-line-or-beginning-search
zle -N up-line-or-beginning-search
zle -N down-line-or-beginning-search

# up
bindkey '^[[A' up-line-or-beginning-search
# down
bindkey '^[[B' down-line-or-beginning-search


###############
# PURE PROMPT #
###############

# initialize the prompt system
fpath+=/opt/homebrew/share/zsh/site-functions
autoload -U promptinit
promptinit
prompt pure

# max execution time of a process before its run time is shown when it exits
PURE_CMD_MAX_EXEC_TIME=10

# change the path color
zstyle :prompt:pure:path color blue

# turn on git stash status
zstyle :prompt:pure:git:stash show yes


###################
# AUTOSUGGESTIONS #
###################

source /opt/homebrew/share/zsh-autosuggestions/zsh-autosuggestions.zsh

# suggestion strategy
ZSH_AUTOSUGGEST_STRATEGY=(history completion)

# add forward-word widgets to PARTIAL_ACCEPT
ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS+=(forward-word)

# right
bindkey '^[[C' forward-word


####################
# COLOURED MANUALS #
####################

man() {
  env \
    LESS_TERMCAP_mb=$(printf '\e[1;31m') \
    LESS_TERMCAP_md=$(printf '\e[1;31m') \
    LESS_TERMCAP_me=$(printf '\e[0m') \
    LESS_TERMCAP_se=$(printf '\e[0m') \
    LESS_TERMCAP_so=$(printf '\e[1;44;33m') \
    LESS_TERMCAP_ue=$(printf '\e[0m') \
    LESS_TERMCAP_us=$(printf '\e[1;32m') \
    man "$@"
}


$ source ~/.zshrc

Si potrebbe fare molto di più, ma per il mio approccio questo è già abbastanza per avere tutto ciò di cui necessito razionalmente installato.

Adesso sì che mi sento a casa!