24 points par GN⁺ 2025-10-23 | 2 commentaires | Partager sur WhatsApp
  • Présentation des scripts shell les plus utilisés parmi les nombreux scripts écrits en plus de 10 ans de maintenance de dotfiles
  • Répartis en presse-papiers, gestion de fichiers, Internet, traitement de texte, lanceurs de REPL, date/heure, audio/vidéo, processus, référence rapide, système et divers, avec pour chaque script un petit wrapper et des exemples concrets
  • La plupart des scripts fonctionnent sur macOS et Linux, avec une philosophie centrale : aplanir les petites frictions agaçantes des outils déjà existants
    • Intégration d’utilitaires standard comme pbcopy/xclip, python3 -m http.server, yt-dlp, ffmpeg, mpv, etc.
  • Parmi les plus utilisés : copy/pasta/pastas/cpwd, mkcd/tempe/trash/mksh, serveit/getsong/getpod/getsubs, scratch/straightquote/markdownquote, timer/boop/tunes, etc.

Présentation des scripts que j’utilise le plus souvent, créés en maintenant mes dotfiles

  • En gérant mes dotfiles personnels depuis plus de 10 ans, j’ai accumulé divers scripts shell que j’utilise fréquemment, ici classés par domaine
  • Chaque script est présenté avec son objectif, sa fréquence d’usage et un exemple représentatif, afin de maximiser sa mise en pratique immédiate
  • L’objectif commun est de réduire les tâches répétitives, abstraire les différences entre plateformes et améliorer la sécurité ainsi que la lisibilité

Scripts liés au presse-papiers

  • copy et pasta : des wrappers autour du gestionnaire de presse-papiers système, basés sur pbcopy sur macOS ou xclip sur Linux
    • copy : copie la sortie dans le presse-papiers
    • pasta : récupère le texte du presse-papiers et l’affiche
    • Exemples : run_some_command | copy, pasta > file.txt, vim "$(pasta)", pasta | base64 --decode
  • pastas : outil qui affiche en temps réel chaque nouveau contenu dès que l’état du presse-papiers change
    • Utile pour enregistrer tous les liens copiés dans un fichier ou télécharger en lot plusieurs liens
    • Exemples : pastas > everything_i_copied.txt, pastas | wget -i -
  • cpwd : copie le chemin du répertoire courant dans le presse-papiers
    • Pratique pour naviguer entre plusieurs onglets de terminal

Scripts de gestion de fichiers

  • mkcd foo : crée un répertoire et s’y déplace immédiatement (raccourci pour mkdir foo && cd foo)
  • tempe : se déplace vers un répertoire temporaire (cd "$(mktemp -d)"), sans besoin de nettoyage après de petits travaux en environnement sandbox
    • Exemple :
      # Download a file and extract it  
      tempe  
      wget 'https://example.com/big_file.tar.xz'  
      tar -xf big_file.tar.xz  
      # ...do something with the file...  
      
      # Write a quick throwaway script to try something out  
      tempe  
      vim foo.py  
      python3 foo.py  
      
  • trash : déplace les fichiers vers la corbeille (compatible macOS/Linux), pour éviter les erreurs par rapport à un simple rm
  • mksh : crée un nouveau fichier de script shell, le rend exécutable et l’ouvre immédiatement dans l’éditeur

Scripts liés à Internet

  • serveit : lance un serveur de fichiers statiques depuis un répertoire local (port 8000 par défaut, avec alternative si Python n’est pas installé)
  • getsong utilise yt-dlp pour télécharger un fichier audio dans la meilleure qualité disponible
  • getpod est un wrapper qui récupère une vidéo sous forme d’audio pour podcast
  • getsubs extrait des sous-titres anglais avec une logique privilégiant les sous-titres officiels puis basculant vers les sous-titres automatiques. Adapté à des usages de pipeline de résumé et de sauvegarde
  • wifi off/on/toggle : contrôle le Wi-Fi système, utile pour résoudre des problèmes réseau
  • url : analyse une chaîne d’URL pour en séparer et extraire le protocole, l’hôte, le chemin, la requête, le hash, etc.

Scripts de traitement de texte

  • line 10 : affiche une ligne précise depuis l’entrée standard (similaire à head et tail)
  • scratch : sert à ouvrir rapidement un tampon de texte temporaire dans Vim, comme avec $EDITOR $(mktemp), pratique pour une note jetable ou une petite transformation
  • straightquote : convertit les guillemets typographiques en guillemets droits, pour éviter les problèmes dans le code et réduire la taille des fichiers
  • markdownquote : ajoute > au début de chaque ligne pour produire une citation Markdown
  • length : renvoie la longueur d’une chaîne en entrée (peut remplacer wc -c)
  • jsonformat : formate joliment des données JSON
  • uppered / lowered : convertissent une chaîne en majuscules / minuscules
  • nato bar : convertit la chaîne fournie en alphabet phonétique OTAN (Bravo Alfa Romeo, etc.)
  • u+ 2025 : affiche le nom et le symbole d’un caractère Unicode
  • snippets foo : récupère un texte abrégé depuis un dictionnaire personnel de snippets
    • snippet arrow donne la flèche →, snippet recruiter un message type comme « not interested »

Lanceurs de REPL

  • Inspirés du irb de Ruby, ils permettent de lancer rapidement un REPL dans divers langages :
    • iclj : Clojure
    • ijs : Deno (ou Node si absent)
    • iphp : PHP
    • ipy : Python
    • isql : SQLite (en mode mémoire depuis Bash)

Scripts de date et d’heure

  • hoy : affiche la date du jour au format ISO (exemple : 2020-04-20), utile comme préfixe de nom de fichier
  • timer 10m : minuteur (10 minutes, etc.), avec son et notification système à la fin
  • rn : affiche proprement l’heure actuelle et le calendrier mensuel via date et cal

Traitement audio, vidéo et image

  • ocr : extrait le texte de fichiers image sur macOS (extension prévue)
  • boop : envoie une alerte sonore selon le succès ou l’échec de la commande précédente, pratique par exemple après un test
  • sfx : joue un fichier d’effet sonore spécifique (.ogg), en lien avec boop et timer
  • tunes : lit des fichiers audio avec mpv (shuffle pris en charge)
  • pix : affiche des photos avec mpv
  • radio : lanceur rapide pour des stations de radio Internet favorites
  • speak : lit le texte reçu sur stdin après suppression du Markdown, puis le passe en synthèse vocale (TTS)
  • shrinkvid : compresse des fichiers vidéo avec ffmpeg
  • removeexif : supprime les données EXIF d’un JPEG, avec prise en charge d’autres formats prévue plus tard
  • tuivid : permet de regarder des vidéos dans le terminal, peu utilisé en pratique mais original

Gestion des processus

  • each : alternative à xargs et find ... -exec, pour exécuter plus facilement des commandes complexes
  • running foo : recherche les processus en cours via un mot-clé donné (PID, commande, etc.) et les affiche dans un format lisible
  • murder : wrapper autour de kill, qui tente un arrêt progressif en partant de signaux doux jusqu’au forçage. Utile pour éviter les erreurs lors d’une demande d’arrêt de programme
  • waitfor $PID : attend qu’un PID donné se termine, en restant éveillé jusque-là
  • bb my_command : lance une commande dans un vrai mode arrière-plan, adapté aux démons et processus similaires
  • prettypath : affiche $PATH avec des retours à la ligne pour une lecture plus claire, utile pour le débogage
  • tryna my_command / trynafail my_command : répètent une commande jusqu’au succès (run until success) ou jusqu’à l’échec (run until fail), applicables à divers scénarios d’automatisation comme le réseau

Outils de référence rapide

  • emoji : recherche et affiche des emoji par mot-clé
  • httpstatus : affiche la liste complète des codes de statut HTTP et permet de consulter l’explication d’un code précis
  • alphabet : affiche toutes les lettres de l’alphabet anglais en minuscules et majuscules, étonnamment utile au quotidien

Administration système

  • theme 0 / theme 1 : change le thème global du système (sombre / clair), avec intégration à Vim, Tmux, etc.
  • sleepybear : met le système en veille (macOS, Linux)
  • ds-destroy : supprime récursivement les fichiers .DS_Store, utile pour nettoyer les dossiers utilisateur sur macOS

Divers

  • catbin foo : affiche directement le code source d’un fichier présent dans le PATH
  • notify : envoie une notification au niveau du système, pratique lorsqu’un long traitement est terminé
  • uuid : génère un UUID version 4

Conclusion

  • Les scripts présentés ici sont des outils que l’auteur utilise réellement très souvent
  • Les scripts de raccourcis faits maison sont très efficaces pour gagner du temps, éviter les erreurs et améliorer la productivité
  • Il est recommandé de créer et utiliser ses propres scripts d’automatisation

2 commentaires

 
GN⁺ 2025-10-23
Commentaires Hacker News
  • La commande trash a.txt b.png envoie les fichiers a.txt et b.png à la corbeille, avec prise en charge sur Mac et Linux. Ma méthode précédente les traitait séquentiellement, donc on entendait le son de suppression pour chaque fichier et seul le dernier pouvait être restauré avec ⌘Z dans Finder. On peut l’améliorer, mais en pratique il est plus simple d’utiliser la commande officielle trash intégrée à macOS. Comme je n’utilise pas Finder, il n’y a ni son ni restauration via ⌘Z, mais c’est plus rapide et la fonction « Put Back » marche aussi. Et pour le pretty-print JSON, au lieu de node on peut utiliser jq avec beaucoup moins de code, et sur les versions récentes de macOS jq est préinstallé. Même chose pour l’affichage d’un UUID : si l’on veut un UUID v4, uuidgen fait très bien l’affaire (voir la page de manuel)

    • Il vaut souvent mieux utiliser les fonctions intégrées que des scripts maison. Par exemple, dans vim, au lieu d’utiliser markdownquote, il suffit de sélectionner la première colonne avec ctrl-v puis de faire i> suivi d’échap. C’est plus court et plus efficace. Je me demande pourquoi u+ 2025 renvoie ñ alors que la vraie valeur Unicode est U+00F1. Et catbin foo revient à faire cat "$(which foo)". Si vous utilisez zsh, cat =foo est plus court et plus puissant. Avec zsh, l’autocomplétion fonctionne après =, donc c’est sûr même avec des commandes longues. J’utilise souvent des choses comme file =firefox ou vim =myscript.sh

    • Je suppose que l’auteur ne connaissait pas uuidgen. C’est justement ce que j’aime quand on partage ce genre de connaissances ou de configuration : ça révèle toujours mes angles morts, d’où l’importance du partage

    • Python sait aussi pretty-printer du JSON par défaut

      $ echo '{ "hello": "world" }' | python3 -m json.tool
      {
        "hello": "world"
      }
      
    • Merci pour l’info sur trash. Jusqu’ici, j’envoyais plusieurs fichiers à la corbeille avec AppleScript, du genre tell app \"Finder\" to move {%s} to trash

    • Comme alternative à rm et trash, je recommande aussi rip lien vers le projet rip

  • Le cycle de vie d’un développeur est assez fascinant. Au début, on reste sur un environnement shell vanilla, puis après 1 ou 2 ans on écrit des centaines de lignes de scripts et d’alias bash. Aujourd’hui, après 15 ans, j’utilise au contraire le shell de base autant que possible, sans alias, et je réserve les choses complexes à Python ou Go

    • Cette tendance tient peut-être moins à une forme d’illumination qu’à la paresse, tout simplement (je dis ça parce que je fais pareil). Grâce aux collègues qui creusent les environnements personnalisés, j’apprends souvent de nouveaux outils, et j’ai récemment ajouté sur Linux des outils comme atuin et fzf

    • J’écris des alias et des fonctions dans mes dotfiles pour enregistrer et mémoriser les commandes que j’utilise souvent. Je continue d’actualiser ma boîte à outils, et c’est facile à transférer sur une nouvelle workstation

    • Quand je n’avais qu’une seule machine nix, j’avais envie de beaucoup personnaliser. Maintenant que j’en utilise plusieurs en parallèle, j’uniformise l’environnement en n’installant que les paquets nécessaires

    • Même ce qui est écrit en Python, je continue à l’appeler un script. À mon avis, le terme script ne se limite pas aux scripts shell

    • Ces temps-ci, en travaillant avec de jeunes ingénieurs, quand je les vois utiliser plusieurs dotfiles, je me dis « moi aussi je faisais ça avant, et c’était pénible ». Maintenant, j’utilise les outils de manière sélective et j’adapte ce qu’il faut avec souplesse. Je respecte aussi les styles des autres

  • J’adore trouver ce genre de billets pleins d’astuces pratiques sur HN. Je suis curieux de voir comment les autres développeurs travaillent vraiment et ce que je pourrais apprendre puis appliquer. Au début, on pense « je n’en aurai sans doute pas besoin », mais dès qu’une tâche devient plus simple, cette tâche elle-même crée un nouveau workflow. Donc j’essaie d’abord, puis je garde ce qui me convient. J’aime aussi le style du billet d’origine : le fait d’indiquer la fréquence réelle d’utilisation est vraiment pratique. Pour les tâches simples, il m’arrive souvent d’ouvrir les devtools du navigateur et de finir ça en JavaScript. (Par exemple pour passer une chaîne en minuscules.)

    • Il serait intéressant de faire une vraie cost-benefit analysis en comparant le temps requis par la méthode de l’auteur et la mienne, ainsi que le coût de création, mémorisation, consultation et migration des scripts

    • Cette image de pense-bête des raccourcis Bash m’aide beaucoup

  • À la place du script line, sed est plus simple pour afficher une ligne précise

    sed -n 2p file
    

    Cela permet d’afficher la deuxième ligne. Pour plusieurs lignes aussi :

    sed -n 2,4p file
    

    donc c’est plus avantageux qu’un script line

    • J’ai souvent besoin d’enchaîner plusieurs commandes sed. À chaque fois, il faut alors modifier en continu la première commande sed. Parfois il faut même un grep avant sed, et découper avec cat, tail et head donne plus de souplesse en utilisant chaque fonction comme un module. C’est conforme à la philosophie Unix qui veut que chaque outil fasse une seule chose
  • J’ai quelques scripts simples que j’utilise souvent. Par exemple :

    #!/usr/bin/env bash
    # ~/bin/,dehex
    
    echo "$1" | xxd -r -p
    
    #!/usr/bin/env bash
    # ~/bin/,ht
    
    highlight() {
      # Couleurs : 30=noir, 31=rouge, 32=vert, ...
      escape=$(printf '\033')
      sed "s,$2,${escape}[$1m&${escape}[0m,g"
    }
    
    if [[ $# == 1 ]]; then
      highlight 31 $1
    elif [[ $# == 2 ]]; then
      highlight 31 $1 | highlight 32 $2
    elif [[ $# == 3 ]]; then
      highlight 31 $1 | highlight 32 $2 | highlight 35 $3
    elif [[ $# == 4 ]]; then
      highlight 31 $1 | highlight 32 $2 | highlight 35 $3 | highlight 36 $4
    fi
    

    Je préfixe mes scripts personnels avec une virgule , pour y basculer rapidement. J’ai l’impression qu’il est utile de faire régulièrement des statistiques sur mes scripts personnels à partir de l’historique, puis de supprimer ceux que je n’utilise plus

  • Je n’ai pas encore réussi à en faire quelque chose de général, mais j’utilise déjà le script unmv de façon assez pratique

    #!/bin/sh
    if test "$#" != 2
    then
      echo 'Error: unmv must have exactly 2 arguments'
      exit 1
    fi
    exec mv "$2" "$1"
    
  • Il y a beaucoup de bonnes astuces, mais en général j’apprends et j’utilise surtout les utilitaires standard (sed, awk, grep, xargs, etc.). La raison, c’est que je travaille sur plusieurs systèmes, et mes scripts personnels comme mes alias n’y sont généralement pas installés. Avec les utilitaires standard, on peut faire presque tout

    • Je suis tout à fait d’accord. On finit par n’utiliser que des standards pour pouvoir travailler partout. Cela dit, les très bons outils finissent parfois par être préinstallés ou faciles à installer via apt-get. Je pense qu’une forme de paquet bien maintenu est préférable à une collection de scripts personnels
  • Je partage mon script d’extraction préféré

    # ex - archive extractor
    # usage: ex <fichier>
    function ex() {
      if [ -f $1 ] ; then
      case $1 in
        *.tar.bz2) tar xjf $1 ;;
        *.tar.gz) tar xzf $1 ;;
        *.tar.xz) tar xf $1 ;;
        *.bz2) bunzip2 $1 ;;
        *.rar) unrar x $1 ;;
        *.gz) gunzip $1 ;;
        *.tar) tar xf $1 ;;
        *.tbz2) tar xjf $1 ;;
        *.tgz) tar xzf $1 ;;
        *.zip) unzip $1 ;;
        *.Z) uncompress $1;;
        *.7z) 7z x $1 ;;
        *) echo "'$1' cannot be extracted via ex()" ;;
      esac
      else
        echo "'$1' is not a valid file"
      fi
    }
    
    • J’aimerais aussi créer le pendant inverse pour compresser

    • Moi, j’utilise dtrx, et j’aime bien le fait qu’il décompresse automatiquement dans un dossier

    • Je trouve aunpack plus pratique

    • Vraiment propre

    • Avec inotify et un service systemd user en plus, ce serait l’étape suivante. Il en existe déjà des versions packagées. Le faire soi-même donne un peu une impression de roue carrée (réinvention)

  • J’ai deux fonctions que j’utilise tout le temps pour l’encodage et le découpage de mp4. Grâce aux flags, la compatibilité est maximale avec divers environnements comme WhatsApp ou Discord mobile

    ffmp4() {
      input_file="$1"
      output_file="${input_file%.*}_sd.mp4"
    
      ffmpeg -i "$input_file" -c:v libx264 -crf 33 -profile:v baseline -level 3.0 -pix_fmt yuv420p -movflags faststart "$output_file"
    
      echo "Compressed video saved as: $output_file"
    }
    
    ffmp4 foo.webm  # conversion en foo_sd.mp4
    
    fftime() {
      input_file="$1"
      output_file="${input_file%.*}_cut.mp4"
      ffmpeg -i "$input_file" -c copy -ss "$2" -to "$3" "$output_file"
    
      echo "Cut video saved as: $output_file"
    }
    
    fftime foo.mp4 01:30 01:45  # crée foo_cut.mp4
    

    fftime découpe rapidement sans réencoder la source, mais selon la vidéo il peut y avoir de légers problèmes (lecture impossible, etc.). Pour réencoder, il suffit d’enlever -c copy

  • Quand je crée et teste des alias ou des fonctions, j’aime pouvoir recharger ~/.zshrc immédiatement, donc j’utilise cet alias

    alias vz="vim ~/.zshrc && . ~/.zshrc"
    

    Et sur Mac, j’utilise cette fonction pour faire du grep dans des fichiers docx

    docgrep() {
      mdfind "\"$@\"" -onlyin /Users/xxxx/Notes 2> >(grep --invert-match ' [UserQueryParser] ' >&2) | grep -v -e '/Inactive/' | sort
    }
    

    J’utilise aussi la fonction ci-dessous pour anonymiser le presse-papiers de mon Mac avant de le coller dans ChatGPT, Slack interne ou d’autres canaux publics, à des fins de débogage. Comme la fonction affiche le nouveau contenu transformé sur stdout après exécution, je peux vérifier s’il reste quelque chose à masquer

    anonymizeclipboard() {
      my_user_id=xxxx
      account_ids="1234567890|1234567890" #regex
      corp_words="xxxx|xxxx|xxxx|xxxx|xxxx" #regex
      project_names="xxxx|xxxx|xxxx|xxxx|xxxx" # regex
      pii="xxxx|xxxx|xxxx|xxxx|xxxx|xxxx" # regex
      hostnames="xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx|xxxx" # regex
      pbpaste | sed -E -e 's/([0-9]{1,3})\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/\1.x.x.x/g' \
      -e "s/(${corp_words}|${project_names}|${my_user_id}|${pii}|${hostnames})/xxxx/g" -e "s/(${account_ids})/1234567890/g" | pbcopy
      pbpaste
    }
    alias anon=anonymizeclipboard
    
    • C’est vraiment excellent. Ce genre de situation m’arrive souvent et je galérais faute de bonne méthode
 
krepe90 2025-10-24

Cela me fait aussi penser à ce billet publié sur GeekNews, Ask GN : avez-vous des snippets shell que vous utilisez souvent ?