为什么这个相当简单的“如果”不起作用?

为什么这个相当简单的“如果”不起作用?

这是我的脚本:

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

它应该寻找第二个参数,删除电位.two,然后将其与 进行比较load,如果是load,则应设置keyaNXlye1tGbd0uP。然而,这不起作用。这就是我运行它时的样子。

pskey Decrypt load (some string)

这是以下的输出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

但是,如果我删除之后的内容[[ "$1" == "Decrypt" ]],它就会起作用。那条线有什么问题吗?

答案1

如果我理解正确的话,你正在寻找这样的东西:

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

请注意,您还可以将整个事情简化为:

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

答案2

terdon 的声明“这远非‘简单’ if。”是轻描淡写。正如约翰·库格曼指出&&||具有相同的优先级,并且从左到右处理。  BinaryZebra 提出了这个想法将布尔表达式转换为级联if语句。我尽力“简化”

如果 A && B ||光盘
然后
        结果=0
别的
        结果=1

如果一个
然后
        如果 B
        然后
                如果D                                        
                然后
                        结果=0
                别的
                        结果=1
        别的
                如果C
                然后
                        如果D
                        然后
                                结果=0
                        别的
                                结果=1
                别的
                        结果=1
别的
        如果C
        然后
                如果D
                然后
                        结果=0
                别的
                        结果=1
        别的
                结果=1

非常远从简单。从上面你可能可以看出,它不起作用的原因是,(在标记线上)如果 A 和 B 都为真,它仍然继续测试 D ( [[ "$1" == "Encrypt" ]])。

正如 BinaryZebra 所显示的,但没有提及,您在 sh/bash 脚本中使用一些类似数学的符号;例如,你可以说

如果(A && B)|| (光盘)
然后

或者,在代码的稍微简化版本中,

如果[[“$2”==“加载”]] && [[“$1”==“解密”]]  ||  [[“$2”==“加载”]] && [[“$1”==“加密”]]
然后

其特点是括号中的代码在子 shell 中运行。如果这是一个问题,您可以使用大括号代替:

如果{[[“$2”==“加载”]] && [[“$1”==“解密”]]; }  ||  {[[“$2”==“加载”]] && [[“$1”==“加密”]]; }
然后

注意,;之前必须有一个} (可以选择用空格分隔),并且之前和之后{、之后都必须有空格}

当然,您应该使用其他答案中提出的技术简化你的测试,例如不是做两次相同的测试$2

有关的:管道和重定向与析取、连接等的绑定优先级?什么时候不需要“如果”?

答案3

在你的代码中:

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

sed 调用可以简化为:${2%?two}if 替换位于变量的末尾$2。请理解,点(.)在 sed 中表示的“任何字符”相当于模式中的问号(?)(感谢@terdon)。如果需要对所有出现的 进行替换.two,那么我们应该使用:"${2//?two}"。然后我们得到这个较短的版本:

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

这是在做什么if A && B || C && D

当 A 为真(load = load)时,B 被执行。如果 B 为真(Decrypt = Decrypt),则跳过
下面的短语 (C), 然后执行 D(Decrypt = Encrypt)。 其结果(最后执行的命令)为一个值。 然后执行......||

false
else

我怀疑你的意思是if ( A && B ) || ( C && D ), as 与A相同C,与 完全相同if ( A && B ) || ( A && D ),可以简化(使用分配财产) 到
if A && ( B || D )

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

“$key”的测试-z可以简化为简单的扩展:key="${key:-$2}"

而且,也许,它会更具可读性(IMO),如下所示:

if A; then
      if   B || D; then

翻译过来是这样的:

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

或者可以使用@terdon的想法,写成这样:

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

请注意,这也是等效的:

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

括号并不是严格必需的,但添加它是为了强制执行以下想法:在[[测试内部,您可以为测试添加空白(制表符、空格、换行符)和括号,从而为测试提供结构。这在测试中效果不一样[

答案4

首先:

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

但你的if布尔逻辑是倒退的:

#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

这里省略第二个&&,因为它不是一个因素 - 它的结果始终与第一个相同。它在这个逻辑链中是一个无用的东西。

这不太有效——一个失败的案例打破了你的陈述。在第一个测试为假的任何情况下,您都会对其返回进行或运算,而不是 (De|En)crypt 测试。事实上,第一个甚至不会发生,因为它被短路了加载返回。因此,您需要首先执行 OR 运算,并通过延迟昂贵的命令替换来利用短路,直到您确实需要对其进行测试为止:

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

所有这些都通过了您的逻辑,如果前两个语句都为假,则甚至不会尝试命令替换。

这是可移植的,带有caseexpr

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

if

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

只是expr&&||,因为if对你来说没有多大作用:

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

也许有grep

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

相关内容