Por que esse simples "se" não funciona?

0

Aqui está o meu script:

if [[ "$(echo "$2" | sed 's/.two//g')" == "load" ]] && [[ "$1" == "Decrypt" ]] || [[ "$(echo "$2" | sed 's/.two//g')" == "load" ]] && [[ "$1" == "Encrypt" ]] 
then
    key=aNXlye1tGbd0uP
else
    if [ -z "$key" ]
    then
        key="$2"
    fi
fi

Ele deve procurar o segundo argumento, remover o potencial .two e, em seguida, compará-lo a load . Se for load , ele deverá definir key a aNXlye1tGbd0uP . No entanto, isso não funciona. Isso é o que parece quando eu o executo.

pskey Decrypt load (some string)

Aqui está a saída de bash -x :

++ echo load
++ sed s/.two//g
+ [[ load == \l\o\a\d ]]
+ [[ Decrypt == \D\e\c\r\y\p\t ]]
+ [[ Decrypt == \E\n\c\r\y\p\t ]]
+ '[' -z '' ']'
+ key=load

No entanto, se eu remover o que está depois de [[ "$1" == "Decrypt" ]] , funciona. O que há de errado com essa linha?

    
por DisplayName 28.12.2015 / 23:31

4 respostas

7

Se eu entendi corretamente, você está procurando algo como isto:

if [[ "$(echo "$2" | sed 's/.two//g')" == "load" && "$1" == "Decrypt" ]] || 
   [[ "$(echo "$2" | sed 's/.two//g')" == "load" && "$1" == "Encrypt" ]]
then
    ...
fi

Note que você também pode simplificar tudo para:

 if [[ "$(echo "$2" | sed 's/.two//g')" == "load" && "$1" =~ (De|En)crypt ]]; then ...
    
por 28.12.2015 / 23:54
1

declaração de terdon «Isso está muito longe de ser um" simples " if .» é um subavaliação. Como John Kugelman apontou , && e || têm igual precedência e são manipulados da esquerda para a direita. BinaryZebra ofereceu a ideia de traduzir expressões booleanas em instruções if em cascata. Minha melhor tentativa de "simplificar"

if A && B || C && D
then
        result=0
else
        result=1
fi

é

if A
then
        if B
        then
                if D                                        
                then
                        result=0
                else
                        result=1
                fi
        else
                if C
                then
                        if D
                        then
                                result=0
                        else
                                result=1
                        fi
                else
                        result=1
                fi
        fi
else
        if C
        then
                if D
                then
                        result=0
                else
                        result=1
                fi
        else
                result=1
        fi
fi

Muito longe do simples. Como você pode ver acima, a razão pela qual isso não funciona é que, (na linha marcada) se A e B são ambos verdadeiros, continua a testar D ( [[ "$1" == "Encrypt" ]] ).

Como BinaryZebra mostra sem mencionar, você pode usar alguma notação matemática nos scripts sh / bash; por exemplo, você pode dizer

if (A && B) || (C && D)
then
  ︙ 

ou, na versão ligeiramente simplificada do seu código,

if ( [["$2" == "load" ]] && [[ "$1" == "Decrypt" ]] )  ||  ( [[ "$2" == "load" ]] && [[ "$1" == "Encrypt" ]] )
then
  ︙ 

Uma característica disso é que o código entre parênteses é executado em um subshell. Se isso for um problema, você pode usar chaves:

if { [["$2" == "load" ]] && [[ "$1" == "Decrypt" ]] ; }  ||  { [[ "$2" == "load" ]] && [[ "$1" == "Encrypt" ]] ; }
then
  ︙ 

Observe que deve haver um ; antes do } (opcionalmente separados por espaço em branco), e deve haver espaços em branco antes e depois do { e depois do } .

Of course you should use the techniques presented in the other answers for simplifying your test, such as not doing the same test on $2 twice.

Relacionados: Canais e amp; precedência de ligação de redirecionamento com disjuntos, Conjuntos, etc.? e Quando é que “se” não é necessário?

    
por 29.12.2015 / 10:27
1

No seu código:

if    [[ "$(echo "$2" | sed 's/.two//g')" == "load" ]] &&
      [[ "$1" == "Decrypt" ]]                          ||
      [[ "$(echo "$2" | sed 's/.two//g')" == "load" ]] &&
      [[ "$1" == "Encrypt" ]] 

A chamada sed pode ser simplificada para apenas: ${2%?two} se a substituição estiver no final da variável $2 . Por favor, entenda que o "qualquer caractere" que o ponto (.) Representa em sed, é equivalente ao ponto de interrogação (?) Em padrões (obrigado @terdon). Se a substituição precisar ser feita para todas as ocorrências de .two , devemos usar: "${2//?two}" . Então nós começamos esta versão mais curta:

if [[ "${2//?two}" == "load" ]]  &&  [[ "$1" == "Decrypt" ]]  ||
   [[ "${2//?two}" == "load" ]]  &&  [[ "$1" == "Encrypt" ]] 

que está fazendo if A && B || C && D .

Quando A é verdadeiro (load = load) B é executado.
Se B for verdadeiro (Descriptografar = Descriptografar), a seguinte frase || (C) será ignorada e
então D é executado (Decrypt = Encrypt).
Quais resultados (o último comando executado) em um valor false .
Então o else é executado .....

Suspeito que o que você quer dizer seja if ( A && B ) || ( C && D ) , que, como A é igual a C , é exatamente igual a if ( A && B ) || ( A && D ) , que pode ser simplificado (usando a propriedade distributiva ) para o% if A && ( B || D ) :

if      [[ "${2//?two}" == "load" ]] &&
      ( [[ "$1" == "Decrypt" ]]   ||  [[ "$1" == "Encrypt" ]]  );
then
      key=aNXlye1tGbd0uP
else
      if    [ -z "$key" ]
      then  key="$2"
      fi
fi

O teste -z para "$ key" pode ser simplificado para uma expansão simples: key="$ {key: - $ 2}"

E, talvez, seria mais legível (IMO) assim:

if A; then
      if   B || D; then

Que se traduz assim:

if           [[ "${2//?two}" == "load" ]]
then   if    [[ "$1" == "Decrypt" ]]   ||  [[ "$1" == "Encrypt" ]]
       then  key=aNXlye1tGbd0u
       else  key="${key:-$2}"
       fi
else         key="${key:-$2}"
fi

Ou poderia, usando a ideia de @ terdon, ser escrito assim:

if           [[ "${2//?two}" == "load" ]] &&
             [[ "$1" =~ (De|En)crypt ]]
then         key=aNXlye1tGbd0u
else         key="${key:-$2}"
fi

Por favor, note que isto também é equivalente:

if       [[  ( "${2//?two}" == "load" ) &&
             ( "$1" =~ (De|En)crypt )
         ]]
then         key=aNXlye1tGbd0u
else         key="${key:-$2}"
fi

Os parênteses não são estritamente necessários, mas adicionados para reforçar a idéia de que dentro de [[ test você poderia estruturar seus testes adicionando espaço em branco (tabulação, espaço, nova linha) e parênteses. Isso não funciona da mesma forma em [ tests.

    
por 29.12.2015 / 00:08
-1

Em primeiro lugar:

[[ $1:$2 =~ ^(En|De)crypt:(.two)*load(.two)*$ ]] && echo conditions met

Mas sua lógica booleana if está invertida:

#sed    #En=$1   #De=$1
true  && false || true    # passes your logic
true  && true  || NA      # passes your logic
false && NA    || false   # fails  your logic
false && NA    || true    # fails  your logic

O segundo && é omitido aqui porque não é um fator - seu resultado é sempre o mesmo que o primeiro. É um noop nesta cadeia lógica.

Isso não funciona bem - o único caso de falha quebra sua afirmação. Em qualquer um desses casos em que o primeiro teste é falso, você acaba retornando seu retorno ao invés dos testes de criptografia (De | En). E, de fato, o primeiro deles nem sequer ocorre porque está em curto-circuito pelo retorno load . Então você quer fazer as ORs primeiro, e aproveitar o curto-circuito atrasando a dispendiosa substituição de comandos até que você definitivamente precise testá-la:

#En=$1  #De=$1   #sed
false || false && NA
false || true  && false
false || true  && true
true  || NA    && false
true  || NA    && true

Todos estes passam a sua lógica e a substituição do comando nem sequer é tentada se ambas as duas primeiras declarações forem falsas.

Aqui está portably w / case e expr :

case  ${2%oad*}:${1%crypt}  in
(:${key:=$2}*|*ad*|*:"$1")  ;;
(*l:De|*l:En)  expr " $2" :  \
" \(\(.two\)*\(load\)*\)*$" &&
     key=aNXlye1tGbd0uP
esac >/dev/null   

e if :

if   [ Encrypt = "$1" -o Decrypt = "$1" ] &&
     expr " $2" : " \(.two\)*load\(.two\)*$"
then key=$newkey
else key=${key:-$2}
fi   >/dev/null

E apenas expr e &&|| , porque o if não faz muito por você:

expr   > /dev/null       \
 "${#1} ${1%crypt}  $2" :\
 "7 \(\(De\)*\(En\)*\) ""\
 \(.two\)*load\(.two\)*$" &&
key=$newkey || key=${key:-$2}

Talvez w / grep :

grep -xqE '(En|De)crypt:(.two)*load(.two)*' \
<<VAR &&   key=$newkey || key=${key:-$2}
${1##*:*}:$2
VAR
    
por 29.12.2015 / 02:27

Tags