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:
$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}
.) for
est beaucoup mieux pour ça. $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.
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).
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.
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.