Eu tenho um script de shell chamado 'teleport.sh' assim:
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
Quando executo:
sh teleport.sh 2 testfile
Isso testfile
é movido para o ~/lab/Sun
diretório, o que me confunde muito porque eu não passei 1 ou '1' para esse script.
O que há de errado aqui?
$var
,$(cmd)
e até mesmo`cmd`
[para o qual$(cmd)
deve ser preferido]). Existem alguns casos extremos em que você não precisa citar, mas sempre isso não fará mal.$(cmd)
é substituição de comando , (principalmente) o mesmo que`cmd`
. Veja mywiki.wooledge.org/CommandSubstitution e mywiki.wooledge.org/BashFAQ/082Respostas:
O uso de espaços corrige seu problema.
Embora isso seja mais puro:
fonte
$1="1"
sintaxe original "funciona" (produzindo um resultado verdadeiro). Como o[
/test
builtin realmente interpreta essa expressão?test
vê apenas um argumento (um "valor l"). Sem os outros argumentos (um "operador" e um "valor-r"), não há nada a testar, entãotest
apenas diz "ok, bem, sim, você me deu algo e isso deve ser vacuamente verdadeiro".$1="1"
é$1
concatenado por=1
A primeira coisa óbvia é que você deve fornecer espaços entre os argumentos de
[
,test
ou[[
:No Bash, o uso
[[ ]]
é recomendado, pois não faz coisas desnecessárias para a expressão condicional, como divisão de palavras e expansão do nome do caminho. Também não é necessário citar aspas duplas. Um operador mais legível==
também pode ser usado.Nota acrescentou: Se segundo operando também contém variáveis, citando é necessária, pois podem estar sujeitos a correspondência de padrão se ele contém personagens reconhecíveis como
*
,?
,[]
, etc .. Se estendida englobamento ou correspondência padrão é ativado comshopt -s extglob
, outras formas como@()
,!()
, etc. também será reconhecido como padrões. Consulte Correspondência de padrões .Com operadores como
<
e>
ainda pode ser necessário, pois uma vez encontrei um bug em que não citar o segundo argumento causou resultados diferentes.Quanto ao primeiro operando, nada se aplica.
Considere também essa variação mais simples:
Ou condensado:
"${@:2}"
é uma forma de expansão de substring ou expansão de membro da matriz onde2
está o deslocamento. Isso faz com que a expansão comece com o segundo valor. Com isso, talvez não precisemos usarshift
.O
--
item adicionado impede omv
reconhecimento de nomes de arquivos iniciados por dash (-
) como opções inválidas.fonte
;&
vez de;;
(apenas ksh, bash, zsh). Mas,break
ainda assim, não impede a queda,break
é apenas romper os loops.if
mas para o[
comando.[[ $foo == $bar ]]
fará a correspondência de padrões, mas[[ $foo == "$bar" ]]
não fará.Para responder à pergunta de por que isso está acontecendo, esse comportamento de
[
akatest
está documentado no POSIX :Você está passando um argumento,
2=1
que não é nulo e, portanto,test
sai com sucesso.Como outras postagens (e verificação de shell ) apontam, se você quiser comparar a igualdade, terá que passar os 3 argumentos
2
,=
e1
.fonte
Eu só quero recomendar uma alternativa portátil, mas também mais limpa. O Bash não é universal (e se você não precisa de universal, por que está escrevendo um shell script?)
(Observação para os pedantes: sim, eu sei que as citações
$action
nacase "$action" in
linha são desnecessárias, mas acho que é melhor colocá-las lá de qualquer maneira, para que futuros leitores não precisem se lembrar disso.)fonte
/bin/sh
scripts portáteis , se precisar; caso contrário, escreva em uma linguagem de script menos terrível que o shell. De fato, o intérprete básico de Perl tem maior probabilidade de estar presente em ambientes proprietários herdados e em ambientes incorporados reduzidos do que o Bash.