Forum Programmation.shell Wrapper for ALSA recording of playback device

Posté par  . Licence CC By‑SA.
Étiquettes :
3
4
oct.
2023

Salut touT le mond0e,

Je souhaite soumettre ce script à votre analyse. Il fonctionne comme je veux même s’il n’est pas fini (pas de getopts notamment) mais je voulais le soumettre à vos critiques, parfois acerbes mais toujours constructives !

#!/bin/bash
test "${1}" || { echo -e "\nUsage: ${0} <file>\n"; exit 1; }

if test -f "${1}"; then
   REC_OUTPUT_FILE="$$-${1}"
else
   REC_OUTPUT_FILE="${1}"
fi

REC_DEVICE='hw:0,1'
REC_FORMAT='S32_LE'
REC_SAMPLERATE='96000'
REC_NB_CHANNELS='2'
FLAC_COMPRESSION_LEVEL='8'

a_period_passed() {
    # 10 seconds by default
    local period="${1:-10}"
    test $(( "$(date +%s)" % period )) -eq 0
}

get_elapsed_time() {
    echo -n "$(date +%H:%M:%S -u -d@"$(( $(date +%s) - REC_START_TIME ))")"
}

get_file_size() {
    du -sh "${1}" | awk '{print $1}'
}

convert_to_flac() {
    wait
    echo -e "\nConvertion to FLAC…"
    mv "${1}" "/tmp/$$-${1}"
    sox -t wav "/tmp/$$-${1}" -t flac -C"${FLAC_COMPRESSION_LEVEL}" "${1}"
    retval="$?"
    rm "/tmp/$$-${1}"
    return "${retval}"
}

stop_recording() { 
    [[ "${REC_OUTPUT_FILE}" =~ .*\.flac$ ]] && convert_to_flac "${REC_OUTPUT_FILE}"
    echo -e "\nAudio recorded to “${REC_OUTPUT_FILE}” (size: $(get_file_size "${REC_OUTPUT_FILE}")) [$(file "${REC_OUTPUT_FILE}" | cut -d':' -f2 | sed -e 's/^\s//')]"; exit
}

arecord -D"${REC_DEVICE}" -f"${REC_FORMAT}" -r"${REC_SAMPLERATE}" -c"${REC_NB_CHANNELS}" "${REC_OUTPUT_FILE}" &> /dev/null &
REC_START_TIME="$(date +%s)"
echo "Recording from device ${REC_DEVICE} at ${REC_SAMPLERATE} Hz on ${REC_NB_CHANNELS} channel(s) to file “${REC_OUTPUT_FILE}”"
echo "Hit Ctrl+C to end recording"
while true; do
    echo -n '.'
    sleep 1
    a_period_passed && echo -en "\n$(get_elapsed_time)|$(get_file_size "${REC_OUTPUT_FILE}")"
    trap stop_recording SIGINT
done

exit 0

Il ya un warning shellcheck qui me laisse dubitatif :

record_loopback.sh:53:5: note: Use a_period_passed "$@" if function's $1 should mean script's $1. [SC2119]

J’ai envie de répondre : « Non ¹ ici here isn’t main script $1, pourquoi tu me casses les couilles ici mais pas pour, entre autres, la fonction get_file_size ? »

Le shell, en l’occurrence bash, est un language interprété que beaucoup dédaignent, lui préférant des langages plus élégants, plus modernes, tels que Python ou Perl. Moi je vous avoue que pour avoir pratiqué les trois, je préfère clairement, finalement, les illogismes de bash/sh, ses aspects barbares et son manque rationalité. Parce que même si c’est moins productif, c’est aussi beaucoup plus palpitant.

  • # timeout ?

    Posté par  . Évalué à 2.

    Question peut-être bête, mais est-ce que avec timeout tu ne peux pas simplifier drastiquement la gestion du temps ? Genre :

    timeout 10s arecord ...
    
    • [^] # Re: timeout ?

      Posté par  . Évalué à 3.

      Ah et je vois que arecord a directement une option -d, --duration=# qui permet de donner une durée directement en secondes, aussi.

      Si tu souhaites déclencher un enregistrement rapidement, j'avais vu un paquet sur Debian, dont j'ai oublié le nom, qui permettait en substance de déclencher un enregistrement de l'audio quelques secondes avant qu'on lance la commande !

      En gros, il y a un démon qui tourne et converse l'audio dans un buffer circulaire de plusieurs secondes/minutes en permanence, et un second outil qui permet de capturer ce buffer et de prolonger l'enregistrement. Comme ça, quand on entend un truc intéressant, on peut l'enregistrer a posteriori.

      • [^] # Re: timeout ?

        Posté par  . Évalué à 2.

        J'ai retrouvé, c'est timemachine mais c'est un plugin Jack, moins simple que ALSA.

        • [^] # Re: timeout ?

          Posté par  . Évalué à 5.

          Yes je connais. Une appli très astucieuse.

          Jack, moins simple que ALSA.

          Quelque part Jack permet de faire des choses de manière plus simple qu’ALSA, et sans devoir arrêter la reproduction du flux audio pour recharger une nouvelle configuration. Parce qu’ALSA, rien que pour permettre d’avoir ce « playback device », c’est franchement cryptique comme configuration à mettre en place. Je me demande d’ailleurs pourquoi il n’existe pas une appli pour configurer ALSA de manière plus intuitive que l’édition directe du fichier de configuration.

          Évidemment le confort apporté par Jack a un coût en terme d’utilisation CPU. Je l’utilise parfois, mais quand je travaille sur un logiciel « monolithique » comme LMMS, j’apprécie de ne pas avoir Jack qui me prend une partie de la ressource CPU.

          Si ça intéresse quelqu’un : la configuration d’ALSA qui permet d’enregistrer le son qui est envoyé à la carte son. Autant j’ai appris à utiliser Jack de façon intuitive, autant pour faire ça avec ALSA je n’y serais sûrement jamais arrivé sans le lien ci-dessus.

          • [^] # Re: timeout ?

            Posté par  . Évalué à 1.

            Si ça intéresse quelqu’un : la configuration d’ALSA qui permet d’enregistrer le son qui est envoyé à la carte son.

            Oui moi, mais quelle usine !

            Pipewire serait-il la solution ?

            "Si tous les cons volaient, il ferait nuit" F. Dard

            • [^] # Re: timeout ?

              Posté par  . Évalué à 4.

              Je ne me suis pas encore penché sur Pipewire, je croyais que c’était un bête "drop-in replacement" de Pulseaudio, mais à priori c’est un projet de serveur audio visant à remplacer Jack et Pulseaudio, une solution universelle pour mettre tout le monde d’accord !?

              Oui moi, mais quelle usine !

              Tu m’étonnes ! Clairement pas adapté à l’utilisateur final. C’est pour ça que je suis surpris qu’il y ai pas une belle GUI pour générer un asound.conf qui va bien pour tel ou tel usage.

              Et Jack parlons-en, en réalité il n’y a pas Jack, il y a Jack 1 et Jack 2, chacun ayant des fonctionnalités que l’autre n’a pas.

    • [^] # Re: timeout ?

      Posté par  . Évalué à 3.

      Je ne fais pas vraiment de gestion du temps. Une fois l’enregistrement démarré, il se poursuit indéfiniment jusqu’à interruption par un Ctrl+C. La fonction a_period_passed elle me sert juste à afficher à intervalle régulier à quelle durée on est rendu, avec la taille du fichier atteinte jusqu’ici.

      Mais merci pour la commande timeout, je ne la connaissais pas (ou plus probablement oublié son existence). Mais comme dit plus bas, arecord prévoit déjà qu’on puisse enregistrer seulement pour une période donnée avec l’option -d.

      Je devrais d’ailleurs peut-être l’utiliser pour définir une période maximum, de sécurité, parce que sinon, même si la source audio cesse, si on oublie d’arrêter le processus il doit se poursuivre jusqu’à saturation de l’espace disque.

  • # Passage explicite du paramètre

    Posté par  . Évalué à 3.

    J'ai essayé sur ma machine, et en fait la remarque fonctionne avec un autre warning :

    a_period_passed() {
    ^-- SC2120 (warning): a_period_passed references arguments, but none are ever passed.
    

    Donc il te recommande de passer un paramètre à a_period_passed() explicitement pour éviter tout ambiguïté sur la nature de $1, des fois que tu croies que $1 est le premier paramètre de ligne de commande (perso je me suis fait avoir). Ta fonction met une valeur par défaut, donc pas de problème de programmation à ce niveau.

    Il ne dit rien pour get_file_size() car tu passes le paramètre et $1 est donc défini sans l'ombre d'un doute, pas la peine de houspiller le programmeur :).

    Sinon, oui désolé, j'avais lu un peu en diagonale et cru que tu voulais couper au bout de $1 secondes. Bref.

    • [^] # Re: Passage explicite du paramètre

      Posté par  . Évalué à 3.

      Ah OK ! Donc le warning dont je parlais est une conséquence du fait de ne pas passer l’argument pourtant prévu (le warning que tu indiques, que j’avais aussi mais dont je n’ai pas jugé bon de parler vu que je le comprenais).

      Un grand merci à toi.

    • [^] # Re: Passage explicite du paramètre

      Posté par  . Évalué à 3.

      perso je me suis fait avoir.

      C’est ça tout le charme du shell, c’est rempli de pièges tous plus saugrenus les uns que les autres ! ^^

      Il est vrai que j’ai pris l’habitude (mais je ne l’ai pas fait ici, à tort) ds systématiquement mettre un commentaire au tout début du corps de la fonction du genre:

      #1: ça
      #2: ceci
      #3: cela
      

      ça aide…

      Le dernier piège dans lequel je suis tombé il y quelques temps : un nombre qui commence par 0 est de l’octal. Si tu utilises le format +V% de date pour récupérer le numéro de la semaine tu as un bug qui survient uniquement pour un mois sur douze, pour septembre ! :)

  • # Remarques

    Posté par  . Évalué à 2. Dernière modification le 06 octobre 2023 à 18:35.

    1. Le trap devrait être avant la boucle. Un seul suffit.
    2. L’affichage du temps passé me paraît inutilement compliqué et le modulo sans intérêt. On peut se contenter de réactualiser l’affichage toutes les n secondes avec un simple sleep et faire sauter « a_period_passed ». Et tu mets à jours toutes les secondes sans manger de ligne (pas de caractère \n linefeed).
    3. arecord capture SIGINT qui est retransmis au process du groupe du shell (tous les processus fils qui ont leur PGID égal au PID du shell), ça explique pourquoi il s’arrête. Mais dans le cas général ce n’est pas garanti, et c’est un peu perturbant de ne pas avoir un arrêt explicite (un sleep à la place du arecord n’est pas interrompu chez moi et continue à tourner en tâche de fond — rattaché au PID 1, lorsque le script exit). D’un autre côté la solution “propre” me paraît singulièrement compliquée.
    4. Nonobstant le très moche /tmp/$$-$1 en lieu et place d’un mktemp tu ne devrais pas, pour éviter les I/O inutiles passer par tmp. Lors des mv il faut privilégier les déplacements dans le même répertoire, pour rester sur le même filesystem (en protégeant par mv -n ... || exit 1 afin de ne rien écraser par inadvertance — l’option est très probablement robuste sur Linux car il suffit d’un appel C à renameat2 avec RENAME_NOREPLACE, mais pas en standard POSIX — faut passer par un mkdir dans ce cas).
    5. Y’a moyen d’éviter les basheries et de faire du POSIX. Pour les extensions je teste "${path%.flac}" != "$path"
    6. awk est overkill, pour faire un cut -f1
    7. -e pour tester l’existence d’un fichier, pas -f. L’intention est louable mais casse-gueule (l’utilisateur peut créer un fichier entre le test et le arecord). Encore une fois mktemp -p, mv -n, ou mkdir fournissent les garanties nécessaires.
    8. J’aime bien en début de shell faire : PATH="$1" (par exemple). Ça auto-documente les arguments de la ligne de commande.
    stop_job() {
        # on préfère SIGHUP qui ne provoque pas un retour d’erreur de la part de arecord
        kill -s SIGHUP $job && wait
        post_process_record
        exit $RC
    }
    # setsid permet de détacher la session du arecord de la session du shell
    # en conséquence le shell n’envoie plus SIGINT à arecord lorsque l’utilisateur saisit ^C
    setsid arecord $REC_ARG &
    job=$!
    trap stop_job SIGINT
    while sleep 10; do printf '\r%s - %s' `du -sh ... |cut -f1` "`elapsed_time`" >&2; done
    • [^] # Re: Remarques

      Posté par  . Évalué à 1. Dernière modification le 06 octobre 2023 à 18:44.

      Pour mon 8. c’est pas une bonne idée de nommer la variable PATH ^^

      • [^] # Re: Remarques

        Posté par  . Évalué à 3. Dernière modification le 07 octobre 2023 à 02:08.

        Oui mais est-ce que ce n’est pas « dommage » d’effectuer une affectation de variable inutile ? Je pense notamment au cas d’une fonction, qui pourrait être appelée de manière intensive (ce qui n’est pas le cas ici mais je parle dans le cas général). Après je ne sais pas, c’est peut-être négligeable.

        • [^] # Re: Remarques

          Posté par  . Évalué à 3.

          Deux programmes simples, avec un million d'exécutions d'une fonction :

          ~ $ cat var.sh
          #!/bin/bash
          
          function something() {
              param=$1
              return
          }
          
          echo "avec assignation"
          for i in {1..1000000}; do
              something $1
          done
          
          ~ $ cat novar.sh
          #!/bin/bash
          
          function something() {
              return
          }
          
          echo "sans assignation"
          for i in {1..1000000}; do
              something $1
          done
          

          Sur ma machine, la version avec assignation prend presque toujours une seconde de plus que celle sans assignation. Genre 6 secondes au lieu de 5, ce qui est en effet énorme !

          Dans un langage compilé, précompilé ou avec du JIT, c'est sans doute moins un sujet. Le même genre de programme en C prend sans doute moins de quelques millisecondes (flemme totale d'essayer).

          • [^] # Re: Remarques

            Posté par  (site web personnel, Mastodon) . Évalué à 4.

            Dans tous les cas, l’affectation a un coût (certes négligeable) ; et si tu ne le ressens pas dans ton programme compilé ce sera plutôt du aux optimisations… (où le compilateur aura probablement généré le même code en détectant qu’il y a une affectation inutile.) :)

            “It is seldom that liberty of any kind is lost all at once.” ― David Hume

            • [^] # Re: Remarques

              Posté par  . Évalué à 4.

              Finalement j'ai fait le test en C, et mon ordi met 5ms pour un million d'itérations, et 2,4s pour 1 milliard.

              void something(int a) {
                  return;
              }
              
              void main(void) {
                  unsigned long long i;
                  for(i = 1; i <= 1000000000 ; i++) {
                      something(1);
                  }
              }

              Mais comme tu dis, si je précise -O2 ou -O3, ça devient inférieur à la milliseconde, car l'optimiseur supprime alors la boucle et les appels à la fonction, vu que ça ne fait rien.

              On peut voir l'assembleur en faisant cc -S -O2 var.c, ça génère un var.s, pour celles et ceux qui ne connaissent pas.

    • [^] # Re: Remarques

      Posté par  . Évalué à 3.

      Pour 6, on ne peut pas faire un cut -d"\n", on peut faire un cut en mettant une tabulation (en utilisant Ctrl+v), mais dans un script je trouve ça pas terrible. Et je crois que j’ai bêtement crû que c’était une suite d’espaces…

      Tu m’apprends qu’on n’a pas besoin d’indiquer un délimiteur. Et que cut se débrouille. Merci !

      Je me pencherai sûrement sur les autres remarque un de ces quatre mais pour ce soir, c’est mort. ^^

      • [^] # Re: Remarques

        Posté par  . Évalué à 2.

        Au besoin, $'\t' est interprété comme un tab.

      • [^] # Re: Remarques

        Posté par  (site web personnel, Mastodon) . Évalué à 3. Dernière modification le 07 octobre 2023 à 18:08.

        Tu m’apprends qu’on n’a pas besoin d’indiquer un délimiteur. Et que cut se débrouille.

        Je n’ai pas compris cela, et si c’était l’intention bah c’est faux : il y a une valeur par défaut, la tabulation, quand on n’indique pas de délimiteur. No magic, RTFM.

        on peut faire un cut en mettant une tabulation (en utilisant Ctrl+v),

        Comme ton script est en bash, tu peux utiliser cut -d $'\t' comme mentionné par un autre commentaire. Mais bon, comme c’est le délimiteur par défaut, pas besoin de s’embêter…
        Par contre, oui :

        on ne peut pas faire un cut -d"\n"

        It's not a bug, that's by designpour la simple et bonne raison que la commande opère sur les lignes

        mais dans un script je trouve ça pas terrible. Et je crois que j’ai bêtement crû que c’était une suite d’espaces…

        C’est hélas un souci courant (pas du tout propre aux scripts shell.) Mon éditeur est toujours configuré pour distinguer visuellement les simples espaces des tabulations.
        Dans le cas présent, on pouvait se douter qu’il s’agit de tabulation (ou d’une erreur qui ne va pas fonctionner) car le délimiteur doit être un caractère !

        “It is seldom that liberty of any kind is lost all at once.” ― David Hume

        • [^] # Re: Remarques

          Posté par  . Évalué à 3. Dernière modification le 07 octobre 2023 à 19:07.

          Je n’ai pas compris cela, et si c’était l’intention bah c’est faux : il y a une valeur par défaut, la tabulation, quand on n’indique pas de délimiteur. No magic, RTFM.

          Oui je me suis mal exprimé.

          J’ai tendance à sortir systématiquement awk au lieu de cut (et c’est une mauvaise habitude je reconnais) du fait que parfois les données à traiter ont des champs séparées par un nombre variables d’espaces (du moins plusieurs), et cut, si on lui indique l’espace comme séparateur, considère alors qu’il s’agit de plusieurs champs vides. Comportement qui a sûrement une bonne raison d’être, mais que je ne saisi pas. Alors que awk considère les espaces multiples comme un seul séparateur.

          cut -d $'\t' […] c’est le délimiteur par défaut, pas besoin de s’embêter…

          Je n’avais effectivement pas en tête que la tabulation était le délimiteur par défaut (en plus d’avoir assumé qu’il s’agissait d’espaces multiples sans même vérifer). Je suis pétri de honte, je vais recopier cent fois le manuel de bash pour expier ma faute.

          Ça reste intéressant à connaître, on peut par exemple faire :

          $ echo -e "plop\0toto" | cut -d $'\0' -f2
          toto

          • [^] # Re: Remarques

            Posté par  . Évalué à 4.

            Au passage, ça peut servir, pour couper sur les espaces multiples et les tabs, je fais souvent cette séquence :

            echo $un_truc | tr -s ' \t' ' ' | cut -d ' ' -f 1,2,3,5,7,11,13,17

            Le -s de tr "squeeze" les répétitions.

            Je ne sais pas à quel moment ça devient plus rentable de sortir sed, awk ou Perl pour le faire avec des regex, ceci dit.

            • [^] # Re: Remarques

              Posté par  . Évalué à 3.

              Sympa l’option -s. J’ai pour habitude, pour faire cela, d’utiliser sed -e 's/\s\s*/ /g', qui est à mon avis moins lisible.

              Je ne sais pas à quel moment ça devient plus rentable de sortir sed

              En tous cas pour simplement « squeezer » les espaces/tabulations multiples tr doit être plus rentable que sed. Parce que le programme fait un peu moins de la moitié de sed en taille, donc j’imagine en temps de chargement (?), et faisant moins de choses je suppose également qu’il est plus simple et s’exécute donc plus vite. Ça doit commencer à s’inverser si tu utilises sed pour faire d’autres transformations, des transformations qu’il faudrait sinon réaliser par de multiples pipes recourant à différents programmes simples tels que tr.

              • [^] # Re: Remarques

                Posté par  (site web personnel, Mastodon) . Évalué à 4.

                Je présume que tu utilise l’implémentation GNU sed car il me semble (mais faut que je vérifie) que \s n’est pas standard…

                Pour la performance, ce n’est pas lié qu’à la taille (qui reste un atout important au niveau du chargement et de l’exécution quand il y a de la charge) mais plus aux actions effectuées (et avec quels algorithmes.)
                TR va parcourir le flot et faire des remplacements à la volée (du moins c’était aussi trivial avant de devoir prendre en compte les encodages multiple octets.)
                SED doit séquentiellement parcourir les lignes du fichier en retenir celles qui correspondent puis appliquer le traitement demandé à la ligne. Cette approche est par nature forcément plus lente.
                Il y a typiquement des choses que les petits utilitaires ne savent pas faire (par exemple substituer un caractère par un autre c’est bon, mais remplacer un mot par un autre non), et en général (presque tout) ce que tu ferais manuellement dans un éditeur de texte sied à Sed …qui a été pensé comme pendant de scriptage de Ed/Ex. D’un autre côté, les enchaînements de pipe ne sont plus performants quand il y en a trop (j’ai compté une dégradation à partir de cinq sur une vieille bécane il y a longtemps, et puis de toute façon pour la gestion des erreurs on repassera) et surtout sur de gros volumes. Là, pouvoir faire dans le même programme plutôt que plusieurs processus qui s’attendent est mieux.

                “It is seldom that liberty of any kind is lost all at once.” ― David Hume

          • [^] # Re: Remarques

            Posté par  (site web personnel, Mastodon) . Évalué à 3.

            et cut, si on lui indique l’espace comme séparateur, considère alors qu’il s’agit de plusieurs champs vides. Comportement qui a sûrement une bonne raison d’être, mais que je ne saisi pas.

            C’est que la plupart de ces outils viennent d’une époque où les choses devaient être KISS et là il s’agit de pouvoir manipuler des fichiers DSV tous bêtes (contrairement à cette immondice de CSV…) Un exemple connu de ce type est le fichier /etc/passwd (et aussi la variable PATH) avec -d ':'

            jsmith:x:1001:1000:Joe Smith,Room 1007,(234)555-8910,(234)555-0044,email:/home/jsmith:/bin/sh

            l’équivalent pour Markdown, sauce GFM et similaires, serait avec -d '|'

            jsmith|x|1001|1000|Joe Smith,Room 1007,(234)555-8910,(234)555-0044,email|/home/jsmith|/bin/sh

            et tu pourrais avoir une application qui utilise des espaces, soit -d ' '
            (dans tous les cas, il faut éviter la collision de délimiteur —par exemple avec le blanc souligné ici mais ce pourrait être un autre espacement comme l’insécable)

            jsmith x 1001 1000 Joe_Smith,Room_1007,(234)555-8910,(234)555-0044,email /home/jsmith /bin/sh

            Avec ce type de format, DSV, la convention a toujours été que tous les champs soient présents, même vides. Dans ce cas, on a deux successions de délimiteur…

            jsmith:x:1001:1000::/home/jsmith:/bin/sh

            …règle qui ne change pas selon le délimiteur (on a dit kiss, pas avec des exceptions comme en français)

            jsmith x 1001 1000  /home/jsmith /bin/sh

            (dans cet exemple, en ayant changé le délimiteur, on ne casse pas notre cut -d ' ' -f 6 héhé)

            Alors que awk considère les espaces multiples comme un seul séparateur.

            C’est un poil plus subtil. Quand AWK ont mis au point l’outil, c’était pour traiter des fichiers avec une structuration un peu plus complexe et ils ont prévu de pouvoir pratiquement tout définir (comprendre décrire le format du fichier…) Du coup, au lieu de travailler ligne par ligne, leur programme gobe tout le fichier et se fait un tableau interne dont les lignes sont découpées au niveau de la valeur de RS (qui est le saut de ligne par défaut) et les colonnes/champs (cette fois-ci variables —i.e. contrairement à du DSV toutes les lignes ne sont pas obligées d’avoir le même nombre de champs) au niveau de FS (qui est toute succession de blancs par défauts, comme la variable IFS pour le shell…) :) Tu as bien un seul séparateur, et c’est là sa différence, le séparateur n’est plus un seul caractère-délimiteur mais une expression rationnelle (soit [:blank:]…)
            C’est à cause de ce traitement plus coûteux que cet utilitaire n’a pas simplement remplacé les autres : chacun répond à des besoins différents, malgré la ressemblance de prime abord.

            • awk -F ' ' '{print $3}' (on utilise comme séparateur de champs, le caractère espace, et non la regexp par défaut) devra te donner le même résultat que cut -d ' ' -f 3
            • awk -F ':' '{print $1}' devra te donner le même résultat que cut -d ':' -f 1

            Ressemblance de prime abord parce-que AWK ont prévu aussi qu’on puisse personnaliser à la sortie/affichage les séparateurs de champs (valeur de OFS qui est par défaut l’espace unique) et d’enregistrement (valeur de ORS qui est par défaut le saut de ligne)

            • awk -F '|' '{print $2,$4}' va, par défaut, afficher les deux champs séparés par une espace… tandis que cut -d '|' -f 2,4 va garder le même séparateur (et il n’est pas prévu de changer cela par défaut sauf en enchainant avec un tr '|' ' ' par exemple.)
            • awk -F ' ' '{print $3,$1}' va bien nous sortir successivement les troisièmes et premiers champs… tandis que cut -d ' ' -f 3,1 est pareil à cut -d ' ' -f 1,3 car les champs ne sont pas réordonnés…

            “It is seldom that liberty of any kind is lost all at once.” ― David Hume

    • [^] # Re: Remarques

      Posté par  (site web personnel, Mastodon) . Évalué à 3.

      Parmi les remarques, aucun commentaire n’a tilté sur la première ligne qui m’a bloquée perso

      test "${1}" || { echo -e "\nUsage: ${0} <file>\n"; exit 1; }

      Il manque l’option du type de test fait, qui je devine est de savoir s’il y a un argument ?

      test -n "${1}" || { echo "Usage: ${0} <file>"; exit 1; }
      # ou alternativement
      test -z "${1}" && { echo "Usage: ${0} <file>"; exit 1; }
      # voire encore
      test $# -lt 1 && { echo "Usage: ${0} <file>"; exit 1; }
      # ou je pense
      test $# -ge 1 || { echo "Usage: ${0} <file>"; exit 1; }

      “It is seldom that liberty of any kind is lost all at once.” ― David Hume

      • [^] # Re: Remarques

        Posté par  . Évalué à 4.

        Extrait du man test :

        CHAÎNE équivalent à -n CHAÎNE

        Mais je note que cela peut potentiellement être déstabilisant.

        • [^] # Re: Remarques

          Posté par  (site web personnel, Mastodon) . Évalué à 2.

          Arf, j’aurais du vérifier avant d’écrire une connerie ^^ En c’est POSIX et il me semble l’avoir déjà rencontré mais bon mon refus des implicites doit faire que j’oublie chaque fois.

          “It is seldom that liberty of any kind is lost all at once.” ― David Hume

          • [^] # Re: Remarques

            Posté par  . Évalué à 3.

            mon refus des implicites

            Ne t’essaie pas à Perl alors, je crois que c’est le langage champion en terme d’implicites (même si on conserve la possibilité d’expliciter dans tous les cas).

            • [^] # Re: Remarques

              Posté par  (site web personnel, Mastodon) . Évalué à 2.

              Ah mais j’en fais et j’aime beaucoup ce langage :D Justement, j’évite les trucs implicites (et du coup je ne comprends pas quand les gens balancent sur Internet que Perl = automatiquement illisible etc.)

              “It is seldom that liberty of any kind is lost all at once.” ― David Hume

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.