Como o comentário de Cachinhos Dourados e as referências da humanidade descrevem,
shift
reatribui os parâmetros posicionais ( $1
, $2
, etc.)
para que $1
assuma o valor antigo de $2
,
$2
assume o valor de $3
, etc. *
O valor antigo de $1
é descartado. ( $0
não é alterado.)
Algumas razões para isso incluem:
- Permite acessar o décimo argumento (se houver) mais facilmente.
$10
não funciona - é interpretado como $1
concatenado com 0
(e assim pode produzir algo como Hello0
).
Depois de um shift
, o décimo argumento se torna $9
.
(No entanto, na maioria dos shells modernos, você pode usar ${10}
.)
- Como o Guia do Bash para iniciantes demonstra,
ele pode ser usado para percorrer os argumentos.
IMNSHO, isso é desajeitado;
for
é muito melhor para isso.
- Como no seu script de exemplo,
torna fácil processar todos os argumentos da mesma maneira, exceto alguns.
Por exemplo, no seu script,
$1
e $2
são cadeias de texto,
enquanto $3
e todos os outros parâmetros são nomes de arquivo.
Então, veja como isso acontece.
Suponha que seu script seja chamado de Patryk_script
e seja chamado de
Patryk_script USSR Russia Treaty1 Atlas2 Pravda3
O script vê
$1 = USSR
$2 = Russia
$3 = Treaty1
$4 = Atlas2
$5 = Pravda3
A instrução ostr="$1"
define a variável ostr
para USSR
.
A primeira instrução shift
altera os parâmetros posicionais da seguinte forma:
$1 = Russia
$2 = Treaty1
$3 = Atlas2
$4 = Pravda3
A instrução nstr="$1"
define a variável nstr
para Russia
.
A segunda instrução shift
altera os parâmetros posicionais da seguinte forma:
$1 = Treaty1
$2 = Atlas2
$3 = Pravda3
Em seguida, o loop for
altera USSR
( $ostr
) para Russia
( $nstr
)
nos arquivos Treaty1
, Atlas2
e Pravda3
.
Existem alguns problemas com o script.
-
for file in $@; do
Se o script for invocado como
Patryk_script USSR Russia Treaty1 "World Atlas2" Pravda3
ele vê
$1 = USSR
$2 = Russia
$3 = Treaty1
$4 = World Atlas2
$5 = Pravda3
mas, como $@
não é citado, o espaço em World Atlas2
não é citado,
e o loop for
acha que tem quatro arquivos: Treaty1
, World
, Atlas2
,
e Pravda3
.
Isso deve ser
for file in "$@"; do
(para citar qualquer caractere especial nos argumentos) ou simplesmente
for file do
(que é equivalente à versão mais longa).
-
eval "sed 's/"$ostr"/"$nstr"/g' $file"
Não é necessário que este seja um eval
,
e passar a entrada do usuário desmarcada para um eval
pode ser perigoso.
Por exemplo, se o script for invocado como
Patryk_script "'; rm *;'" Russia Treaty1 Atlas2 Pravda3
executará rm *
!
Esta é uma grande preocupação se o script puder ser executado
com privilégios superiores aos do usuário que a invoca;
por exemplo, se puder ser executado por meio de sudo
ou invocado em uma interface da web.
Provavelmente não é tão importante se você usá-lo como você mesmo,
no seu diretório.
Mas isso pode ser alterado para
sed "s/$ostr/$nstr/g" "$file"
Isso ainda apresenta alguns riscos, mas eles são muito menos graves.
-
if [ -f $file ]
, > $file.tmp
e mv $file.tmp $file
deve ser if [ -f "$file" ]
, > "$file.tmp"
e mv "$file.tmp" "$file"
,
respectivamente, para manipular nomes de arquivos
que pode ter espaços (ou outros personagens engraçados) neles.
(O comando eval "sed …
também manipula nomes de arquivos que possuem espaços neles.)
* shift
aceita um argumento opcional:
um inteiro positivo que especifica quantos parâmetros para mudar.
O padrão é um ( 1
).
Por exemplo, shift 4
causa $5
para se tornar $1
,
$6
para se tornar $2
e assim por diante.
(Observe que o exemplo no Guia do Bash para iniciantes está errado.)
E assim o seu script pode ser modificado para dizer
ostr="$1"
nstr="$2"
shift 2
que pode ser considerado mais claro.
Nota final / Aviso:
O idioma do Prompt de Comando do Windows (arquivo de lote)
também suporta um comando SHIFT
,
que faz basicamente a mesma coisa que o comando shift
em shells Unix,
com uma diferença marcante,
que eu vou esconder para evitar que as pessoas fiquem confusas com isso:
- A command like
SHIFT 4
is an error,
yielding an “Invalid parameter to SHIFT command” error message.
-
SHIFT /n
, where n
is an integer between 0 and 8,
is valid — but it doesn’t shift n
times.
It shifts once, starting with the n th argument.
So SHIFT /4
causes %5
(the fifth argument) to become %4,
%6
to become %5
, and so on, leaving arguments 0 through 3 alone.