Tengo un script de shell llamado 'teleport.sh' como este:
if [ $1="1" ];
then
shift
mv "$@" ~/lab/Sun
elif [ $1="2" ];
then
shift
mv "$@" ~/lab/Moon
elif [ $1="3" ];
then
shift
mv "$@" ~/lab/Earth
fi
Cuando ejecuto:
sh teleport.sh 2 testfile
Esto testfile
se mueve al ~/lab/Sun
directorio, lo que me confunde mucho ya que no pasé 1 o '1' a ese script.
¿Qué pasa aquí?
$var
,$(cmd)
e incluso`cmd`
[a la que$(cmd)
se debe preferir]). Hay algunos casos extremos en los que no tiene que citar, pero hacerlo siempre no le hará daño.$(cmd)
es la sustitución de comandos , (principalmente) lo mismo que`cmd`
. Ver mywiki.wooledge.org/CommandSubstitution y mywiki.wooledge.org/BashFAQ/082Respuestas:
Usar espacios soluciona tu problema.
Aunque esto es más ordenado:
fuente
$1="1"
sintaxis original "funciona" (produciendo un resultado verdadero). ¿Cómo interpreta realmente[
/test
builtin esa expresión?test
solo ve un argumento (un "valor l"). Sin los otros argumentos (un "operador" y un "valor r"), no hay nada que probar, así quetest
solo dice "ok, bueno sí, me diste algo y eso debe ser completamente cierto".$1="1"
es$1
concatenado por=1
La primera cosa obvia es que debe proporcionar espacios entre los argumentos de
[
,test
o[[
:Cuando está en Bash,
[[ ]]
se recomienda el uso, ya que no hace cosas innecesarias para la expresión condicional, como la división de palabras y la expansión de nombres de ruta. Citar alrededor de comillas dobles tampoco es necesario.==
También se puede utilizar un operador más legible .Se agregó una nota: Si segundo operando también contiene variables, citando es necesario, ya que puede estar sujeta a la coincidencia de patrones si contiene caracteres reconocibles como
*
,?
,[]
, etc .. Si englobamiento extendido o coincidencia de patrones está habilitado conshopt -s extglob
, otras formas como@()
,!()
, etc. También será reconocido como patrones. Ver coincidencia de patrones .Con operadores similares
<
y>
todavía puede ser necesario, ya que una vez me encontré con un error en el que no citar el segundo argumento causaba resultados diferentes.En cuanto al primer operando, no se aplica nada.
Considere también esta variación más simple:
O condensado:
"${@:2}"
es una forma de expansión de subcadena o expansión de miembro de matriz donde2
está el desplazamiento. Esto hace que la expansión comience en el segundo valor. Con esto puede que no necesitemos usarshift
.El agregado
--
impidemv
reconocer nombres de archivo que comienzan con guión (-
) como opciones no válidas.fuente
;&
lugar de;;
(ksh, bash, zsh solamente). Perobreak
aún así no evita la caída,break
es solo salir de los bucles.if
sino para el[
comando.[[ $foo == $bar ]]
realizará la coincidencia de patrones, pero[[ $foo == "$bar" ]]
no lo hará.Para responder a la pregunta de por qué sucede esto, este comportamiento de
[
akatest
está documentado en POSIX :Le está pasando 1 argumento,
2=1
que no es nulo y, por lo tanto,test
sale con éxito.Como señalan otras publicaciones (y shellcheck ), si quisiera comparar por igualdad, en su lugar tendría que pasar los 3 argumentos
2
,=
y1
.fuente
Solo quiero recomendar una alternativa portátil pero también más ordenada. Bash no es universal (y si no necesita universal, ¿por qué está escribiendo un script de shell?)
(Nota para los pedantes: sí, sé que las citas
$action
en lacase "$action" in
línea son innecesarias, pero creo que es mejor ponerlas allí de todos modos, para que los futuros lectores no tengan que recordar eso).fuente
/bin/sh
scripts portátiles , si lo necesita; de lo contrario, escriba en un lenguaje de script que sea menos terrible que el shell. De hecho, es más probable que el intérprete básico de Perl esté presente en entornos propietarios heredados y entornos integrados reducidos que Bash.