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 présume que le script devrait être utilisé avec au moins des arguments, alors ...?
shell-script
arguments
Patryk
la source
la source
pushd
etpopd
).bash
, la question concerne tous les obus. C'est pourquoi le standard Posix prévaut: pubs.opengroup.org/onlinepubs/9699919799/utilities/…Comme le commentaire et les références de l' humanité de Goldilocks décrivent,
shift
réaffecte les paramètres de position ($1
,$2
, etc.) de sorte que$1
prend l'ancienne valeur$2
,$2
prend la valeur$3
, etc. * L'ancienne valeur$1
est mis au rebut. ($0
n'est pas modifié.) Voici quelques raisons pour cela:$10
ne fonctionne pas - il est interprété comme$1
concaténé avec un0
(et peut donc produire quelque chose commeHello0
). Après unshift
, le dixième argument devient$9
. (Cependant, dans la plupart des coquillages modernes, vous pouvez utiliser${10}
.)for
c'est bien mieux pour ça.$1
et$2
sont des chaînes de texte, alors$3
que tous les autres paramètres sont des noms de fichier.Alors, voici comment ça se passe. Supposons que votre script s'appelle
Patryk_script
et s'appelle commeLe script voit
L'instruction
ostr="$1"
définit variableostr
àUSSR
. La premièreshift
instruction modifie les paramètres de position comme suit:L'instruction
nstr="$1"
définit variablenstr
àRussia
. La deuxièmeshift
instruction modifie les paramètres de position comme suit:Et puis les
for
changements en boucleUSSR
($ostr
) àRussia
($nstr
) dans les fichiersTreaty1
,Atlas2
etPravda3
.Il y a quelques problèmes avec le script.
Si le script est appelé en tant que
il voit
mais, parce que
$@
n'est pas cité, l'espaceWorld Atlas2
n'est pas cité, et lafor
boucle pense qu'il a quatre fichiers:Treaty1
,World
,Atlas2
etPravda3
. Cela devrait être soit(pour citer des caractères spéciaux dans les arguments) ou simplement
(ce qui équivaut à la version longue).
Il n'est pas nécessaire que cela soit un
eval
et ileval
peut être dangereux de passer une entrée utilisateur non contrôlée à un . Par exemple, si le script est appelé en tant queça va exécuter
rm *
! Cela peut poser un problème 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é viasudo
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 cela peut être changé enCela comporte encore certains risques, mais ils sont beaucoup moins graves.
if [ -f $file ]
,> $file.tmp
etmv $file.tmp $file
devraient êtreif [ -f "$file" ]
,> "$file.tmp"
etmv "$file.tmp" "$file"
, respectivement, pour gérer les noms de fichiers pouvant contenir des espaces (ou d’autres personnages amusants). (Laeval "sed …
commande modifie également les noms de fichiers contenant des espaces.)*
shift
prend un argument optionnel: un entier positif spécifiant le nombre de paramètres à décaler. La valeur par défaut est un (1
). Par exemple,shift 4
fait$5
devenir$1
,$6
devenir$2
, etc. (Notez que l'exemple du Guide Bash pour les débutants est erroné.) Ainsi, votre script pourrait être modifié pour indiquerqui pourrait être considéré comme plus clair.
Note de fin / Avertissement:
Le langage d'invite de commande Windows (fichier de commandes) prend également en charge une
SHIFT
commande, qui fait essentiellement la même chose que lashift
commande dans les shells Unix, à une différence frappante, que je vais masquer pour éviter que les utilisateurs ne s'y perdent:la source
shift
peut être appliqué àwhile
,until
et même desfor
boucles pour manipuler des tableaux de manière beaucoup plus subtile qu'une simplefor
boucle. Je le trouve souvent utile dans lesfor
boucles du genre ...set -f -- $args; IFS=$split; for arg do set -- $arg; shift "${number_of_fields_to_discard}" && fn_that_wants_split_arg "$arg"; done
L'explication la plus simple est la suivante. Considérez la commande:
Sans l'aide de
shift
vous, vous ne pouvez pas extraire la valeur complète de l'emplacement, car cette valeur peut être arbitrairement longue. Lorsque vous vous déplacez deux fois, les argumentsSET
etlocation
sont supprimés tels que:Jetez un long regard à la
$@
chose. Cela signifie qu’il peut enregistrer l’emplacement complet en variablex
malgré les espaces et la virgule dont il dispose. Donc, en résumé, nous appelonsshift
et, plus tard, nous récupérons la valeur de ce qui reste de la variable$@
.UPDATE J'ajoute ci-dessous un très court extrait montrant le concept et l'utilité
shift
sans lequel il serait très, très difficile d'extraire correctement les champs.Explication : Après le
shift
, la variable b doit contenir le reste du contenu transféré, peu importe les espaces, etc. Il[ -n "$b" ] && echo $b
s'agit d'une protection telle que nous n'imprimons b que si elle a un contenu.la source
"$*"
place de"$@"
. (3) J'allais upvoter votre réponse, mais je ne l'ai pas fait, parce que vous dites «changer deux fois» mais vous ne l'indiquez pas réellement dans le code. (4) Si vous souhaitez qu'un script puisse extraire une valeur de plusieurs mots de la ligne de commande, il est probablement préférable d'exiger de l'utilisateur qu'il mette la valeur entière entre guillemets. … (Suite)Philippines 6014
), des espaces de début, des espaces de fin ou des onglets. (5) BTW, vous pourrez peut-être aussi faire ce que vous faites ici à Bashx="${*:3}"
.shift
commande. Vous faites peut-être allusion aux différences subtiles entre $ @ et $ *. Mais le fait demeure que mon extrait ci-dessus peut extraire avec précision l’emplacement, quel que soit le nombre d’espaces qu’il comporte, soit à l’avant, peu importe. Après le quart de travail, l'emplacement contiendra l'emplacement correct.shift
Traiter les arguments de ligne de commande comme une file d'attente FIFO, c'est un élément popleft chaque fois qu'il est appelé.la source