Forum Programmation.shell Script avec commande wc

Posté par  . Licence CC By‑SA.
Étiquettes : aucune
0
26
nov.
2019

Bonjour,

Il arrive parfois qu'un tracker BitTorrent change son adresse URL.
Utilisant l'excellent mais assez austère client rtorrent, il n'est à ma connaissance pas possible d'éditer cette URL directement depuis le client.
J'ai trouvé sur le Net une ligne avec la commande sed qui fait le boulot.
Voulant rendre cela plus utilisable, je l'ai incluse dans un script.

#!/bin/bash

SOURCE_DIR="/tmp/session"
TARGET_DIR="/tmp/new_session"

SOURCE_TRACKER="http://tracker.example/passkey/announce"
TARGET_TRACKER="toto"

LENGHT_SOURCE_TRACKER="39"
LENGHT_TARGET_TRACKER="4"

cd "$TARGET_DIR"
rm -f *
cd "$SOURCE_DIR"

for i in *.torrent*; do
  cat "$i" | sed 's?'$LENGHT_SOURCE_TRACKER':'$SOURCE_TRACKER'?'$LENGHT_TARGET_TRACKER':'$TARGET_TRACKER'?g' > "$TARGET_DIR/$i"
done

# EOF

Je voudrais que le script calcule tout seule la longueur des variables $SOURCE_TRACKER et $TARGET_TRACKER mais je remarque un problème avec la commande wc.

Quand je compte dans un éditeur de texte le nombre de lettre dans $SOURCE_TRACKER, je trouve 39.
Quand je passe par wc, j'obtiens une valeur différente.

myhost:/tmp $ echo http://tracker.example/passkey/announce | wc -m
40

Avez-vous une idée du pourquoi ?

Merci par avance pour vos suggestions !

  • # newline

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

    La commande echo ajoute automatiquement un retour à la ligne final (\n) ; il existe des options (non-standard) pour éviter cela, mais printf permet de contrôler finalement comment on affiche les choses.

    En passant, length, plutôt que lenght.

    Debian Consultant @ DEBAMAX

    • [^] # Re: newline

      Posté par  . Évalué à 3.

      Je confirme toute l'analyse de Cyril.

      Je tiens tout de même à ajouter que comme le script utilise explicitement bash (mais ça doit aussi fonctionner avec d'autres shell), on peut utiliser les mécanismes internes au shell pour avoir la longueur d'une chaine de caractères :

      echo ${#LENGHT_SOURCE_TRACKER} → 39
      

      Dans ce cas particulier, avec des chaines représentant des URL, il ne devrait pas il y avoir de souci mais si la chaine contient des caractères codés sur plusieurs octets (Utf-8), il faut faire attention à la locale courante, voire au shell utilisé (bash ou wc donneront le bon résultat si la locale est bonne mais dash, par exemple, retournera le nombre d'octets)

      Enfin, concernant l'utilisation de LENGTH à la place de LENGHT dans le nom des variables, je n'ai pas d'opinion ;-)

      • [^] # Re: newline

        Posté par  . Évalué à 1.

        Super pour le comptage de caractères intégré au bash.

        Merci !

    • [^] # Re: newline

      Posté par  . Évalué à 1.

      Merci pour la correction du length.

  • # UUOC

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

    Il y a un petit UUOC.

    Sed peut opérer directement sur un fichier plutôt que de passer par l'entrée standard, ainsi le code pourrait ressembler à

    sed "...comme avant..." "$i" > "$TARGET_DIR/$i"

    Par ailleurs, c'est assez étrange d'utiliser '?' comme délimiteur, étant donné que '?' est un caractère d'expression régulière. Quand on doit manipuler des chemins je pense que c'est plus commun d'utiliser | ou @ (assez fréquent dans les recettes de constructions BSD).

    Exemple :

    sed "s|/bin/bash|/bin/sh|" ...

    git is great because linus did it, mercurial is better because he didn't

    • [^] # Re: UUOC

      Posté par  . Évalué à 3. Dernière modification le 26 novembre 2019 à 13:39.

      Sed peut opérer directement sur un fichier plutôt que de passer par l'entrée standard, ainsi le code pourrait ressembler à

      sed "…comme avant…" "$i" > "$TARGET_DIR/$i"

      Ou au pire, en utilisant stdin: sed "...comme avant..." < $i > "$TARGET_DIR/$i"

      Par contre, dans son cas, ben, j'aurais plutôt utilisé ta construction, pour éviter la boucle for inutile:

      cp -a *.torrent* "$TARGET_DIR/"
      sed -i "$TARGET_DIR/*" -e 's?'$LENGHT_SOURCE_TRACKER':'$SOURCE_TRACKER'?'$LENGHT_TARGET_TRACKER':'$TARGET_TRACKER'?g'
      

      Par ailleurs, c'est assez étrange d'utiliser '?' comme délimiteur, étant donné que '?' est un caractère d'expression régulière.

      Pas si sed est utilisé sans -r/-E/--regexp-externded me semble.

      • [^] # Re: UUOC

        Posté par  (site web personnel) . Évalué à 1.

        Au passage, c'est rigolo de suggérer le remplacement de ? par | au motif (vous l'avez ?) qu'il s'agit d'un caractère spécial dans les expressions rationnelles. ;p

        Debian Consultant @ DEBAMAX

      • [^] # Re: UUOC

        Posté par  . Évalué à 1.

        Merci pour le remplacement du for.

        Par contre il faut faire :

        cp -a *.torrent* "$TARGET_DIR/"
        cd "$TARGET_DIR/"
        sed -i * -e 's?'$LENGHT_SOURCE_TRACKER':'$SOURCE_TRACKER'?'$LENGHT_TARGET_TRACKER':'$TARGET_TRACKER'?g'
        • [^] # Re: UUOC

          Posté par  . Évalué à 2. Dernière modification le 27 novembre 2019 à 18:52.

          Pourquoi changer de dossier? Ça n'a rien d'obligatoire, il suffit d'utiliser le glob dans le dossier cible.

          • [^] # Re: UUOC

            Posté par  . Évalué à 1.

            En copiant la commande j'obtiens un message d'erreur :

            sed: can't read /tmp/.session_new/*: No such file or directory
  • # Commentaire supprimé

    Posté par  . Évalué à 0. Dernière modification le 28 décembre 2019 à 21:18.

    Ce commentaire a été supprimé par l’équipe de modération.

Suivre le flux des commentaires

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