Me he encontrado con este 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
¿Cuál es el significado de las líneas donde se usan shift
? Supongo que el script debe usarse con al menos argumentos, así que ...?
shell-script
arguments
Patryk
fuente
fuente
pushd
ypopd
).bash
, la pregunta es general para todos los shells, por lo tanto, prevalece el estándar Posix: pubs.opengroup.org/onlinepubs/9699919799/utilities/…Como comentario Goldilocks' y las referencias de la humanidad describen,
shift
vuelve a asignar los parámetros de posición ($1
,$2
, etc.) de manera que$1
asume el antiguo valor de$2
,$2
asume el valor de$3
, etc * El antiguo valor de$1
se descarta. ($0
no se cambia). Algunas razones para hacerlo incluyen:$10
no funciona: se interpreta como$1
concatenado con un0
(y, por lo tanto, podría producir algo asíHello0
). Después de ashift
, se convierte en el décimo argumento$9
. (Sin embargo, en la mayoría de los proyectiles modernos, puede usar${10}
).for
es mucho mejor para eso$1
y$2
son cadenas de texto, mientras que$3
y todos los demás parámetros son nombres de archivo.Así es como se desarrolla. Supongamos que su script se llama
Patryk_script
y se llama comoEl guión ve
La declaración
ostr="$1"
establece la variableostr
enUSSR
. La primerashift
declaración cambia los parámetros posicionales de la siguiente manera:La declaración
nstr="$1"
establece la variablenstr
enRussia
. La segundashift
declaración cambia los parámetros posicionales de la siguiente manera:Y a continuación, los
for
cambios de bucleUSSR
($ostr
) aRussia
($nstr
) en los archivosTreaty1
,Atlas2
yPravda3
.Hay algunos problemas con el script.
Si el script se invoca como
ve
pero, debido a
$@
que no es citado, en el espacioWorld Atlas2
no es citado, y elfor
bucle piensa que tiene cuatro archivos:Treaty1
,World
,Atlas2
, yPravda3
. Esto debería ser(para citar cualquier carácter especial en los argumentos) o simplemente
(que es equivalente a la versión más larga).
No hay necesidad de que esto sea un
eval
, y pasar una entrada de usuario no verificada a uneval
puede ser peligroso. Por ejemplo, si el script se invoca comose ejecutará
rm *
! Esto es una gran preocupación si el script se puede ejecutar con privilegios superiores a los del usuario que lo invoca; por ejemplo, si se puede ejecutarsudo
o invocar desde una interfaz web. Probablemente no sea tan importante si solo lo usa como usted mismo, en su directorio. Pero se puede cambiar aEsto todavía tiene algunos riesgos, pero son mucho menos severos.
if [ -f $file ]
,> $file.tmp
ymv $file.tmp $file
debe serif [ -f "$file" ]
,> "$file.tmp"
ymv "$file.tmp" "$file"
, respectivamente, para manejar nombres de archivos que pueden tener espacios (u otros caracteres divertidos) en ellos. (Eleval "sed …
comando también manipula los nombres de archivo que tienen espacios en ellos).*
shift
toma un argumento opcional: un entero positivo que especifica cuántos parámetros cambiar. El valor predeterminado es uno (1
). Por ejemplo,shift 4
hace$5
que se convierta$1
,$6
que se convierta$2
, etc. (Tenga en cuenta que el ejemplo en la Guía Bash para principiantes es incorrecto). Por lo tanto, su secuencia de comandos podría modificarse para decirlo que podría considerarse más claro.
Nota final / Advertencia:
El lenguaje de símbolo del sistema de Windows (archivo por lotes) también admite un
SHIFT
comando, que básicamente hace lo mismo que elshift
comando en shells de Unix, con una notable diferencia, que ocultaré para tratar de evitar que la gente se confunda:fuente
shift
puede aplicarse awhile
,until
e inclusofor
bucles para manejar matrices de formas mucho más sutiles que unfor
bucle simple . A menudo lo encuentro útil enfor
bucles como ...set -f -- $args; IFS=$split; for arg do set -- $arg; shift "${number_of_fields_to_discard}" && fn_that_wants_split_arg "$arg"; done
La explicación más simple es esta. Considere el comando:
Sin la ayuda de
shift
usted, no puede extraer el valor completo de la ubicación porque este valor podría ser arbitrariamente largo. Cuando cambia dos veces, los argsSET
ylocation
se eliminan de manera que:Mire muy largamente la
$@
cosa. Eso significa que puede guardar la ubicación completa en variable ax
pesar de los espacios y la coma que tiene. En resumen, llamamosshift
y luego recuperamos el valor de lo que queda de la variable$@
.ACTUALIZACIÓN Estoy agregando a continuación un fragmento muy breve que muestra el concepto y la utilidad de los
shift
cuales, sin lo cual, sería muy, muy difícil extraer los campos correctamente.Explicación : Después de
shift
, la variable b contendrá el resto de las cosas que se pasan, sin importar espacios o etc. La[ -n "$b" ] && echo $b
protección es tal que solo imprimimos b si tiene un contenido.fuente
"$*"
lugar de"$@"
. (3) Iba a votar su respuesta, pero no lo hice, porque usted dice "cambiar dos veces" pero en realidad no lo muestra en el código. (4) Si desea que un script pueda tomar un valor de varias palabras de la línea de comando, probablemente sea mejor requerir que el usuario ponga el valor completo entre comillas. … (Continúa)Philippines 6014
), espacios iniciales, espacios finales o pestañas. (5) Por cierto, también puedes hacer lo que estás haciendo aquí en golpex="${*:3}"
.shift
comando. Tal vez se refiera a las diferencias sutiles de $ @ versus $ *. Pero el hecho sigue siendo que mi fragmento de arriba puede extraer con precisión la ubicación sin importar cuántos espacios tenga detrás o en el frente, no importa. Después del turno, la ubicación contendrá la ubicación correcta.shift
tratar los argumentos de la línea de comandos como una cola FIFO, es un elemento popleft cada vez que se invoca.fuente