Quel est l'objective d'utiliser le décalage dans les scripts shell?

Je suis tombé sur ce script:

#! /bin/bash if (( $# < 3 )); then echo "$0 old_ssortingng new_ssortingng file [file...]" exit 0 else ostr="$1"; shift nstr="$1"; shift fi echo "Replacing \"$ostr\" with \"$nstr\"" for file in $@; do if [ -f $file ]; then echo "Working with: $file" eval "sed 's/"$ostr"/"$nstr"/g' $file" > $file.tmp mv $file.tmp $file fi done 

et je ne peux pas envelopper ma tête autour des lignes où ils utilisent shift .

Qu'est-ce que cela veut dire? Je suppose que le script devrait être utilisé avec au less des arguments alors …?

    shift est un bash embedded qui élimine les arguments au début de la list des arguments. Étant donné que les arguments fournis au script sont 3 disponibles dans $ 1, $ 2, $ 3, alors un appel à shift fera 2 $ le nouveau $ 1. un shift 2 changera en faisant deux nouveaux $ 1 l'ancien $ 3. pour plus d'informations voir ici

    Shift et réaffecte les parameters de position ( $1 $2 , etc.) pour que $1 prenne l'ancienne valeur de $2 $2 , $2 prenne la valeur de $3 , etc. * L'ancienne valeur de $1 est mis au rebut. ( $0 n'est pas changé). Voici quelques raisons de le faire:

    • Il vous permet d'accéder au dixième argument (s'il y en a un) plus facilement. $10 ne fonctionne pas – il est interprété comme $1 concaténé avec un 0 (et pourrait donc produire quelque chose comme Hello0 ). Après un shift , le dixième argument devient $9 . (Cependant, dans la plupart des shells modernes, vous pouvez utiliser ${10} .)
    • Comme le montre le Bash Guide for Beginners , il peut être utilisé pour parcourir les arguments. IMNSHO, c'est maladroit; for est beaucoup mieux pour ça.
    • Comme dans votre exemple de script, il est facile de traiter tous les arguments de la même manière sauf pour quelques-uns. Par exemple, dans votre script, $1 et $2 sont des strings de text, tandis que $3 et tous les autres parameters sont des noms de file.

    Alors, voici comment ça se passe. Supposons que votre script s'appelle Patryk_script et qu'il s'appelle

     Patryk_script USSR Russia Treaty1 Atlas2 Pravda3 

    Le script voit

     $1 = USSR $2 = Russia $3 = Treaty1 $4 = Atlas2 $5 = Pravda3 

    L'instruction ostr="$1" définit la variable ostr en USSR . La première instruction shift change les parameters de position comme suit:

     $1 = Russia $2 = Treaty1 $3 = Atlas2 $4 = Pravda3 

    L'instruction nstr="$1" définit la variable nstr en Russia . La seconde instruction shift change les parameters de position comme suit:

     $1 = Treaty1 $2 = Atlas2 $3 = Pravda3 

    Et puis la boucle for change USSR ( $ostr ) en Russia ( $nstr ) dans les files Treaty1 , Atlas2 et Pravda3 .



    Il y a quelques problèmes avec le script.

    1.   pour le file dans $ @;  faire 

      Si le script est appelé comme

        Patryk_script URSS Russie Traité1 "World Atlas2" Pravda3 

      il voit

        1 $ = URSS
       2 $ = Russie
       3 $ = Traité1
       4 $ = Atlas mondial2
       5 $ = Pravda3 

      mais, parce que $@ n'est pas cité, l'espace dans World Atlas2 n'est pas cité, et la boucle for pense avoir quatre files: Treaty1 , World , Atlas2 et Pravda3 . Cela devrait être soit

        pour le file dans "$ @";  faire 

      (pour citer des caractères spéciaux dans les arguments) ou simplement

        pour le file do 

      (ce qui équivaut à la version plus longue).

    2.   eval "sed 's /" $ ostr "/" $ nstr "/ g' $ file" 

      Il n'est pas nécessaire que ce soit un eval , et le passage d'une input d'user non contrôlée à un eval peut être dangereux. Par exemple, si le script est appelé comme

        Patryk_script "" rm * "" Russie Traité1 Atlas2 Pravda3 

      il va exécuter rm * ! Ceci est une grande préoccupation si le script peut être exécuté avec des privilèges plus élevés que ceux de l'user qui l'invoque; par exemple, si elle peut être exécutée via sudo ou invoquée à partir d'une interface Web. Ce n'est probablement pas si important si vous l'utilisez comme vous-même, dans votre directory. Mais il peut être changé pour

        sed "s / $ ostr / $ nstr / g" "$ file" 

      Cela comporte encore des risques, mais ils sont beaucoup less graves.

    3. if [ -f $file ] > $file.tmp et mv $file.tmp $file devrait être if [ -f "$file" ] , > "$file.tmp" et mv "$file.tmp" "$file" , respectivement, pour gérer les noms de files qui pourraient avoir des espaces (ou d'autres personnages drôles) en eux. (La command eval "sed … manipule également les noms de files contenant des espaces.)


    * shift prend un argument optionnel: un entier positif qui spécifie le nombre de parameters à décaler. La valeur par défaut est de un ( 1 ). Par exemple, le shift 4 fait $5 deviennent $1 $6 pour $2 et ainsi de suite. (Notez que l'exemple du Bash Guide for Beginners est faux). Votre script pourrait donc être modifié pour dire

     ostr="$1" nstr="$2" shift 2 

    ce qui pourrait être considéré comme plus clair.