diff --git a/src/uu/expr/src/syntax_tree.rs b/src/uu/expr/src/syntax_tree.rs index 4ca723a4d..e0e786b3a 100644 --- a/src/uu/expr/src/syntax_tree.rs +++ b/src/uu/expr/src/syntax_tree.rs @@ -166,16 +166,26 @@ impl AstNode { { let mut out = Vec::with_capacity(operands.len()); let mut operands = operands.iter(); - // check the first value before `|`, stop evaluate and return directly if it is true. - // push dummy to pass the check of `len() == 2` - if op_type == "|" { - if let Some(value) = operands.next() { - let value = value.evaluate()?; - out.push(value.clone()); - if value_as_bool(&value) { - out.push(String::from("dummy")); - return Ok(out); + + if let Some(value) = operands.next() { + let value = value.evaluate()?; + out.push(value.clone()); + // short-circuit evaluation for `|` and `&` + // push dummy to pass `assert!(values.len() == 2);` + match op_type.as_ref() { + "|" => { + if value_as_bool(&value) { + out.push(String::from("dummy")); + return Ok(out); + } } + "&" => { + if !value_as_bool(&value) { + out.push(String::from("dummy")); + return Ok(out); + } + } + _ => {} } } diff --git a/tests/by-util/test_expr.rs b/tests/by-util/test_expr.rs index 4637d51c7..1064ef525 100644 --- a/tests/by-util/test_expr.rs +++ b/tests/by-util/test_expr.rs @@ -155,6 +155,21 @@ fn test_and() { .args(&["-14", "&", "1"]) .run() .stdout_is("-14\n"); + + new_ucmd!() + .args(&["0", "&", "a", "/", "5"]) + .run() + .stdout_only("0\n"); + + new_ucmd!() + .args(&["", "&", "a", "/", "5"]) + .run() + .stdout_only("0\n"); + + new_ucmd!() + .args(&["-1", "&", "10", "/", "5"]) + .succeeds() + .stdout_only("-1\n"); } #[test]