Je suis tombé sur ce script:
#! /bin/bash
if (( $# < 3 )); then
echo "$0 old_string new_string 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
Quelle est la signification des lignes où ils utilisent shift
? Je suppose que le script doit être utilisé avec au moins des arguments alors ...?
shift
est un bash
intégré qui sorte de supprime les arguments du début de la liste des arguments. Étant donné que les 3 arguments fournis au script sont disponibles dans $1
, $2
, $3
, puis un appel à shift
fera $2
le nouveau $1
. UNE shift 2
changera de deux en créant de nouveaux $1
l'ancien $3
. Pour plus d'informations, voir ici:
Comme le décrivent les commentaires de Goldilocks et les références de l'humanité, shift
réattribue les paramètres de position ($1
, $2
, Etc.) afin que $1
Prenne l'ancienne valeur de $2
, $2
prend la valeur de $3
, etc.*L'ancienne valeur de $1
Est supprimée. ($0
N'est pas modifié.) Voici quelques raisons pour cela:
$10
Ne fonctionne pas - il est interprété comme $1
Concaténé avec un 0
(Et peut 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 bien mieux pour ça.$1
Et $2
Sont des chaînes de texte, tandis que $3
Et tous les autres paramètres sont des noms de fichier.Voici comment ça se passe. Supposons que votre script s'appelle Patryk_script
Et qu'il s'appelle comme
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
sur USSR
. La première instruction shift
modifie les paramètres de position comme suit:
$1 = Russia
$2 = Treaty1
$3 = Atlas2
$4 = Pravda3
L'instruction nstr="$1"
Définit la variable nstr
sur Russia
. La deuxième instruction shift
modifie les paramètres de position comme suit:
$1 = Treaty1
$2 = Atlas2
$3 = Pravda3
Et puis la boucle for
change USSR
($ostr
) En Russia
($nstr
) Dans les fichiers Treaty1
, Atlas2
Et Pravda3
.
Il y a quelques problèmes avec le script.
pour le fichier dans $ @; faire
Si le script est appelé en tant que
Patryk_script URSS Traité de Russie1 "Atlas mondial2" 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 qu'elle a quatre fichiers: Treaty1
, World
, Atlas2
et Pravda3
. Cela devrait être soit
pour le fichier dans "$ @"; faire
(pour citer tout caractère spécial dans les arguments) ou simplement
pour le fichier faire
(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 entrée utilisateur non contrôlée à un eval
peut être dangereux. Par exemple, si le script est appelé en tant que
Patryk_script "'; rm *;'" Russia Treaty1 Atlas2 Pravda3
il exécutera rm *
! C'est une grande préoccupation si le script peut être exécuté avec des privilèges supérieurs à ceux de l'utilisateur qui l'invoque; par exemple, s'il peut être exécuté via Sudo
ou appelé à partir d'une interface Web. Ce n'est probablement pas si important si vous l'utilisez comme vous-même, dans votre répertoire. Mais il peut être changé en
sed "s/$ ostr/$ nstr/g" "$ file"
Cela comporte encore certains risques, mais ils sont beaucoup moins graves.
if [ -f $file ]
, > $file.tmp
Et mv $file.tmp $file
Doivent être respectivement if [ -f "$file" ]
, > "$file.tmp"
Et mv "$file.tmp" "$file"
Pour gérer les noms de fichiers qui peut contenir des espaces (ou d'autres personnages amusants). (La commande eval "sed …
Modifie également les noms de fichiers contenant des espaces.)
* shift
prend un argument facultatif: un entier positif qui spécifie le nombre de paramètres à décaler. La valeur par défaut est un (1
). Par exemple, shift 4
Fait que $5
Devient $1
, $6
Devient $2
, Etc. (Notez que l'exemple dans le Bash Guide for Beginners est faux.) Et donc votre script pourrait être modifié pour dire
ostr="$1"
nstr="$2"
shift 2
qui pourrait être considéré comme plus clair.
Note de fin /Avertissement:
Le langage d'invite de commandes Windows (fichier de commandes) prend également en charge une commande SHIFT
, qui fait essentiellement la même chose que la commande shift
dans les shells Unix, avec une différence frappante, que je cacherai essayez d'éviter que les gens ne soient déroutés:
- Une commande comme
SHIFT 4
Est une erreur, générant un message d'erreur "Paramètre non valide pour la commande SHIFT".SHIFT /n
, Oùn
est un entier compris entre 0 et 8, est valide - mais il ne change pasn
fois. Il change une fois, en commençant par l'argument n e. AinsiSHIFT /4
Fait que%5
(Le cinquième argument) devient%4,
%6
Devient%5
, Et ainsi de suite, en laissant les arguments 0 à 3 seul.
L'explication la plus simple est la suivante. Considérez la commande:
/bin/command.sh SET location Cebu
/bin/command.sh SET location Cebu, Philippines 6014
Sans l'aide de shift
, vous ne pouvez pas extraire la valeur complète de l'emplacement car cette valeur pourrait devenir arbitrairement longue. Lorsque vous déplacez deux fois, les arguments SET
et location
sont supprimés de telle sorte que:
x="$@"
echo "location = $x"
Prenez un très long regard sur le $@
chose. Cela signifie qu'il peut enregistrer l'emplacement complet dans la variable x
malgré les espaces et les virgules dont il dispose. Donc en résumé, nous appelons shift
puis nous récupérons plus tard la valeur de ce qui reste de la variable $@
.
UPDATE J'ajoute ci-dessous un extrait très court montrant le concept et l'utilité de shift
sans lequel, il serait très, très difficile d'extraire correctement les champs.
#!/bin/sh
#
[ $# -eq 0 ] && return 0
a=$1
shift
b=$@
echo $a
[ -n "$b" ] && echo $b
Explication: Après le shift
, la variable b doit contenir le reste des éléments transmis, peu importe les espaces ou etc. Le [ -n "$b" ] && echo $b
est une protection telle que nous n'imprimons b que s'il a un contenu.
shift
traite les arguments de ligne de commande comme une file d'attente FIFO, il popleft chaque fois qu'il est invoqué.
array = [a, b, c]
shift equivalent to
array.popleft
[b, c]
$1, $2,$3 can be interpreted as index of the array.
$# is the length of array