1309 lines
26 KiB
YAML
1309 lines
26 KiB
YAML
name: "Options: set -e"
|
|||
|
|
cases:
|
||
|
|
- name: "errexit with set -o errexit"
|
||
|
|
stdin: |
|
||
|
|
set -o errexit
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "errexit status check"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
set -o | grep errexit
|
||
|
|
|
||
|
|
# Basic behavior
|
||
|
|
- name: "Basic non-error case"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
true
|
||
|
|
echo "Text after call"
|
||
|
|
|
||
|
|
- name: "Basic error case"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
false
|
||
|
|
echo "Text after call"
|
||
|
|
|
||
|
|
- name: "Command line -e"
|
||
|
|
args: ["-e"]
|
||
|
|
stdin: |
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "Multiple commands before error"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
echo "first"
|
||
|
|
echo "second"
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "Error in middle of script"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
echo "before"
|
||
|
|
false
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "Error in if condition"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
if false; then
|
||
|
|
echo "then branch"
|
||
|
|
else
|
||
|
|
echo "else branch"
|
||
|
|
fi
|
||
|
|
echo "after if"
|
||
|
|
|
||
|
|
- name: "Error in elif condition"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
if false; then
|
||
|
|
echo "then branch"
|
||
|
|
elif false; then
|
||
|
|
echo "elif branch"
|
||
|
|
else
|
||
|
|
echo "else branch"
|
||
|
|
fi
|
||
|
|
echo "after if"
|
||
|
|
|
||
|
|
- name: "Error in if body"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
if true; then
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
fi
|
||
|
|
echo "after if"
|
||
|
|
|
||
|
|
- name: "Error in elif body"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
if false; then
|
||
|
|
echo "then branch"
|
||
|
|
elif true; then
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
fi
|
||
|
|
echo "after if"
|
||
|
|
|
||
|
|
- name: "Error in else body"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
if false; then
|
||
|
|
echo "then"
|
||
|
|
else
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
fi
|
||
|
|
echo "after if"
|
||
|
|
|
||
|
|
- name: "Error in if condition with compound test"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
if false && false; then
|
||
|
|
echo "then"
|
||
|
|
else
|
||
|
|
echo "else"
|
||
|
|
fi
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "Error in while condition"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
count=0
|
||
|
|
while false; do
|
||
|
|
echo "loop body"
|
||
|
|
done
|
||
|
|
echo "after while"
|
||
|
|
|
||
|
|
- name: "Error in while body"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
count=0
|
||
|
|
while [ $count -lt 2 ]; do
|
||
|
|
count=$((count + 1))
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
done
|
||
|
|
echo "after while"
|
||
|
|
|
||
|
|
- name: "Error in until condition"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
count=0
|
||
|
|
until true; do
|
||
|
|
echo "loop body"
|
||
|
|
done
|
||
|
|
echo "after until"
|
||
|
|
|
||
|
|
- name: "Error in until body"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
until false; do
|
||
|
|
false
|
||
|
|
echo "loop body"
|
||
|
|
break
|
||
|
|
done
|
||
|
|
echo "after until"
|
||
|
|
|
||
|
|
# Boolean operators - set -e should NOT exit with && and ||
|
||
|
|
- name: "Error on right side of &&"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
true && false
|
||
|
|
echo "after &&"
|
||
|
|
|
||
|
|
- name: "Error on left side of &&"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
false && true
|
||
|
|
echo "after &&"
|
||
|
|
|
||
|
|
- name: "Error on both sides of ||"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
false || false
|
||
|
|
echo "after ||"
|
||
|
|
|
||
|
|
- name: "Error on left side of ||"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
false || true
|
||
|
|
echo "after ||"
|
||
|
|
|
||
|
|
- name: "Error on right side of ||"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
true || false
|
||
|
|
echo "after ||"
|
||
|
|
|
||
|
|
- name: "Error after && chain"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
true && true
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "Complex boolean expression"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
false || true && false || true
|
||
|
|
echo "after complex expression"
|
||
|
|
|
||
|
|
- name: "Negated command with failure"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
! false
|
||
|
|
echo "after negation"
|
||
|
|
|
||
|
|
- name: "Negated command with success"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
! true
|
||
|
|
echo "after negation"
|
||
|
|
|
||
|
|
- name: "Error after negated command"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
! false
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
# Pipelines
|
||
|
|
- name: "Error in first command of pipeline (without pipefail)"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
false | true
|
||
|
|
echo "after pipeline"
|
||
|
|
|
||
|
|
- name: "Error in first command of pipeline (without pipefail, negated)"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
! false | true
|
||
|
|
echo "after pipeline"
|
||
|
|
|
||
|
|
- name: "Error in first command of pipeline (with pipefail)"
|
||
|
|
stdin: |
|
||
|
|
set -e -o pipefail
|
||
|
|
false | true
|
||
|
|
echo "after pipeline"
|
||
|
|
|
||
|
|
- name: "Error in first command of pipeline (with pipefail, negated)"
|
||
|
|
stdin: |
|
||
|
|
set -e -o pipefail
|
||
|
|
! false | true
|
||
|
|
echo "after pipeline"
|
||
|
|
|
||
|
|
- name: "Error in middle of pipeline (without pipefail)"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
true | false | true
|
||
|
|
echo "after pipeline"
|
||
|
|
|
||
|
|
- name: "Error in middle of pipeline (without pipefail, negated)"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
! true | false | true
|
||
|
|
echo "after pipeline"
|
||
|
|
|
||
|
|
- name: "Error in middle of pipeline (with pipefail)"
|
||
|
|
stdin: |
|
||
|
|
set -e -o pipefail
|
||
|
|
true | false | true
|
||
|
|
echo "after pipeline"
|
||
|
|
|
||
|
|
- name: "Error in middle of pipeline (with pipefail, negated)"
|
||
|
|
stdin: |
|
||
|
|
set -e -o pipefail
|
||
|
|
! true | false | true
|
||
|
|
echo "after pipeline"
|
||
|
|
|
||
|
|
- name: "Error in last command of pipeline (without pipefail)"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
true | false
|
||
|
|
echo "after pipeline"
|
||
|
|
|
||
|
|
- name: "Error in last command of pipeline (without pipefail, negated)"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
! true | false
|
||
|
|
echo "after pipeline"
|
||
|
|
|
||
|
|
- name: "Error in last command of pipeline (with pipefail)"
|
||
|
|
stdin: |
|
||
|
|
set -e -o pipefail
|
||
|
|
true | false
|
||
|
|
echo "after pipeline"
|
||
|
|
|
||
|
|
- name: "Error in last command of pipeline (with pipefail, negated)"
|
||
|
|
stdin: |
|
||
|
|
set -e -o pipefail
|
||
|
|
! true | false
|
||
|
|
echo "after pipeline"
|
||
|
|
|
||
|
|
- name: "Errors in multiple commands of pipeline (without pipefail)"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
|
||
|
|
function ret() {
|
||
|
|
return $1
|
||
|
|
}
|
||
|
|
|
||
|
|
ret 1 | ret 2 | ret 3
|
||
|
|
|
||
|
|
- name: "Errors in multiple commands of pipeline (without pipefail, negated)"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
|
||
|
|
function ret() {
|
||
|
|
return $1
|
||
|
|
}
|
||
|
|
|
||
|
|
! ret 1 | ret 2 | ret 3
|
||
|
|
|
||
|
|
- name: "Errors in multiple commands of pipeline (with pipefail)"
|
||
|
|
stdin: |
|
||
|
|
set -e -o pipefail
|
||
|
|
|
||
|
|
function ret() {
|
||
|
|
return $1
|
||
|
|
}
|
||
|
|
|
||
|
|
ret 1 | ret 2 | ret 3
|
||
|
|
|
||
|
|
- name: "Errors in multiple commands of pipeline (with pipefail, negated)"
|
||
|
|
stdin: |
|
||
|
|
set -e -o pipefail
|
||
|
|
|
||
|
|
function ret() {
|
||
|
|
return $1
|
||
|
|
}
|
||
|
|
|
||
|
|
! ret 1 | ret 2 | ret 3
|
||
|
|
|
||
|
|
- name: "Pipeline in conditional"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
if true | false; then
|
||
|
|
echo "then"
|
||
|
|
else
|
||
|
|
echo "else"
|
||
|
|
fi
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "Negated pipeline"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
! false | false
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
# Functions
|
||
|
|
- name: "Error in function body exits function and script"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
myfunc() {
|
||
|
|
echo "in function"
|
||
|
|
false
|
||
|
|
echo "should not print in function"
|
||
|
|
}
|
||
|
|
myfunc
|
||
|
|
echo "should not print after function"
|
||
|
|
|
||
|
|
- name: "Function returning error in conditional"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
myfunc() {
|
||
|
|
false
|
||
|
|
}
|
||
|
|
if myfunc; then
|
||
|
|
echo "then"
|
||
|
|
else
|
||
|
|
echo "else"
|
||
|
|
fi
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "Function called with &&"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
myfunc() {
|
||
|
|
false
|
||
|
|
}
|
||
|
|
true && myfunc
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "Function called with ||"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
myfunc() {
|
||
|
|
false
|
||
|
|
}
|
||
|
|
false || myfunc
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "Function called with negation"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
myfunc() {
|
||
|
|
false
|
||
|
|
}
|
||
|
|
! myfunc
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "Error in function body with set -e inside function"
|
||
|
|
stdin: |
|
||
|
|
myfunc() {
|
||
|
|
set -e
|
||
|
|
echo "before error"
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
}
|
||
|
|
myfunc
|
||
|
|
echo "after function call"
|
||
|
|
|
||
|
|
- name: "Function with explicit return still respects set -e"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
myfunc() {
|
||
|
|
false
|
||
|
|
return 0
|
||
|
|
}
|
||
|
|
myfunc
|
||
|
|
echo "after function"
|
||
|
|
|
||
|
|
# Subshells
|
||
|
|
- name: "Error in subshell exits subshell but not parent"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
echo "before subshell"
|
||
|
|
(
|
||
|
|
echo "in subshell"
|
||
|
|
false
|
||
|
|
echo "should not print in subshell"
|
||
|
|
)
|
||
|
|
echo "after subshell"
|
||
|
|
|
||
|
|
- name: "Subshell with set -e exits on error"
|
||
|
|
stdin: |
|
||
|
|
false
|
||
|
|
(
|
||
|
|
set -e
|
||
|
|
echo "before"
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
)
|
||
|
|
echo "after subshell"
|
||
|
|
|
||
|
|
- name: "Subshell failure in conditional"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
if (false); then
|
||
|
|
echo "then"
|
||
|
|
else
|
||
|
|
echo "else"
|
||
|
|
fi
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "Subshell with &&"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
true && (false)
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
# Command substitution
|
||
|
|
- name: "Error in command substitution"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
result=$(false)
|
||
|
|
echo "after command substitution"
|
||
|
|
|
||
|
|
- name: "Error in command substitution with assignment"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
var=$(false; echo "value")
|
||
|
|
echo "var is: $var"
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "Command substitution in conditional"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
if [ "$(false; echo no)" = "no" ]; then
|
||
|
|
echo "matched"
|
||
|
|
fi
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "set +e disables error exit"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
echo "with -e"
|
||
|
|
set +e
|
||
|
|
false
|
||
|
|
echo "after false with +e"
|
||
|
|
|
||
|
|
- name: "set -e can be re-enabled"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
set +e
|
||
|
|
false
|
||
|
|
echo "after false with +e"
|
||
|
|
set -e
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "set +e in function"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
myfunc() {
|
||
|
|
set +e
|
||
|
|
false
|
||
|
|
echo "in function after false"
|
||
|
|
}
|
||
|
|
myfunc
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
# Exit status handling
|
||
|
|
- name: "Non-zero exit status triggers exit"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
(exit 1)
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "Specific non-zero exit status"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
(exit 42)
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "Zero exit status"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
(exit 0)
|
||
|
|
echo "after exit 0"
|
||
|
|
|
||
|
|
# Assignment with command substitution
|
||
|
|
- name: "Assignment from failing command"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
var=$(false) || true
|
||
|
|
echo "after assignment"
|
||
|
|
|
||
|
|
- name: "Local variable assignment with failing command"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
myfunc() {
|
||
|
|
local var=$(false)
|
||
|
|
echo "after local"
|
||
|
|
}
|
||
|
|
myfunc
|
||
|
|
echo "after function"
|
||
|
|
|
||
|
|
# Complex scenarios
|
||
|
|
- name: "Error after successful conditional"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
if true; then
|
||
|
|
echo "in if"
|
||
|
|
fi
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "Nested conditionals with error"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
if true; then
|
||
|
|
if false; then
|
||
|
|
echo "inner then"
|
||
|
|
else
|
||
|
|
echo "inner else"
|
||
|
|
fi
|
||
|
|
echo "after inner if"
|
||
|
|
fi
|
||
|
|
echo "after outer if"
|
||
|
|
|
||
|
|
- name: "Error in case branch"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
case "x" in
|
||
|
|
$(false))
|
||
|
|
echo "matched"
|
||
|
|
;;
|
||
|
|
esac
|
||
|
|
echo "after case"
|
||
|
|
|
||
|
|
- name: "Error in case statement body"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
case "x" in
|
||
|
|
x)
|
||
|
|
echo "matched"
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
;;
|
||
|
|
esac
|
||
|
|
echo "after case"
|
||
|
|
|
||
|
|
- name: "case pattern matching on non-match"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
case "x" in
|
||
|
|
y) echo "y" ;;
|
||
|
|
z) echo "z" ;;
|
||
|
|
esac
|
||
|
|
echo "after case"
|
||
|
|
|
||
|
|
# List constructs
|
||
|
|
- name: "Error in ; list"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
true ; false ; echo "should not print"
|
||
|
|
|
||
|
|
- name: "Semicolon separated commands respect set -e"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
echo "first" ; echo "second" ; false ; echo "should not print"
|
||
|
|
|
||
|
|
# Background jobs
|
||
|
|
- name: "Error in background job"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
false &
|
||
|
|
wait
|
||
|
|
echo "after wait"
|
||
|
|
|
||
|
|
# Interaction with other options
|
||
|
|
- name: "set -e with set -o pipefail"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
set -o pipefail
|
||
|
|
true | false
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "set -e without pipefail allows pipeline errors"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
true | false | true
|
||
|
|
echo "after pipeline"
|
||
|
|
|
||
|
|
# Edge cases with test builtin
|
||
|
|
- name: "test builtin false result in conditional"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
if test 1 -eq 2; then
|
||
|
|
echo "then"
|
||
|
|
else
|
||
|
|
echo "else"
|
||
|
|
fi
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "test builtin false result standalone"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
test 1 -eq 2
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "[ builtin false result in conditional"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
if [ 1 -eq 2 ]; then
|
||
|
|
echo "then"
|
||
|
|
else
|
||
|
|
echo "else"
|
||
|
|
fi
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "[ builtin false result standalone"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
[ 1 -eq 2 ]
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "trap ERR"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
trap 'echo "error trapped"' ERR
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "trap EXIT"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
trap 'echo "exit trapped"' EXIT
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
# Combination of contexts
|
||
|
|
- name: "Error in function in conditional"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
myfunc() {
|
||
|
|
false
|
||
|
|
}
|
||
|
|
if myfunc; then
|
||
|
|
echo "then"
|
||
|
|
else
|
||
|
|
echo "else"
|
||
|
|
fi
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "Negated function call"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
myfunc() {
|
||
|
|
echo "in function"
|
||
|
|
false
|
||
|
|
}
|
||
|
|
! myfunc
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "Function in pipeline on internal error"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
myfunc() {
|
||
|
|
false
|
||
|
|
}
|
||
|
|
myfunc | true
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "Error after function in boolean context"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
myfunc() {
|
||
|
|
false
|
||
|
|
}
|
||
|
|
myfunc || true
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
# Arithmetic constructs with errexit
|
||
|
|
- name: "Arithmetic command (( )) standalone with false result"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
(( 0 ))
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "Arithmetic command (( )) standalone with true result"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
(( 1 ))
|
||
|
|
echo "after arithmetic"
|
||
|
|
|
||
|
|
- name: "Arithmetic command (( )) in if condition"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
if (( 0 )); then
|
||
|
|
echo "then"
|
||
|
|
else
|
||
|
|
echo "else"
|
||
|
|
fi
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "Arithmetic command (( )) with &&"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
(( 0 )) && echo "matched"
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "Arithmetic for loop condition false"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
count=0
|
||
|
|
for ((; count > 0 ;)); do
|
||
|
|
echo "body"
|
||
|
|
done
|
||
|
|
echo "after for loop"
|
||
|
|
|
||
|
|
- name: "Arithmetic for loop with errexit in body"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
for ((i=0; i<2; i++)); do
|
||
|
|
echo "iteration $i"
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
done
|
||
|
|
echo "should not print after loop"
|
||
|
|
|
||
|
|
# Extended test [[ ]] with errexit
|
||
|
|
- name: "Extended test [[ ]] standalone with false result"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
[[ 1 -eq 2 ]]
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "Extended test [[ ]] standalone with true result"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
[[ 1 -eq 1 ]]
|
||
|
|
echo "after test"
|
||
|
|
|
||
|
|
- name: "Extended test [[ ]] in if condition"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
if [[ 1 -eq 2 ]]; then
|
||
|
|
echo "then"
|
||
|
|
else
|
||
|
|
echo "else"
|
||
|
|
fi
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "Extended test [[ ]] with &&"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
[[ 1 -eq 2 ]] && echo "matched"
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "Extended test [[ ]] with ||"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
[[ 1 -eq 2 ]] || echo "not matched"
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
# Brace groups with errexit
|
||
|
|
- name: "Brace group in pipeline with errexit"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
{ false; } | true
|
||
|
|
echo "after pipeline"
|
||
|
|
|
||
|
|
- name: "Brace group in pipeline with pipefail"
|
||
|
|
stdin: |
|
||
|
|
set -e -o pipefail
|
||
|
|
true | { false; }
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "Brace group with internal error and errexit"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
{
|
||
|
|
echo "in brace"
|
||
|
|
false
|
||
|
|
echo "should not print in brace"
|
||
|
|
}
|
||
|
|
echo "should not print after brace"
|
||
|
|
|
||
|
|
# Nested subshells with errexit
|
||
|
|
- name: "Nested subshells with errexit"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
(
|
||
|
|
(
|
||
|
|
false
|
||
|
|
echo "inner should not print"
|
||
|
|
)
|
||
|
|
echo "outer should print - inner exited but does not affect parent"
|
||
|
|
)
|
||
|
|
echo "after subshells"
|
||
|
|
|
||
|
|
- name: "Deeply nested subshells with errexit"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
(
|
||
|
|
(
|
||
|
|
(
|
||
|
|
false
|
||
|
|
echo "level 3 should not print"
|
||
|
|
)
|
||
|
|
echo "level 2 should print"
|
||
|
|
)
|
||
|
|
echo "level 1 should print"
|
||
|
|
)
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
# Functions calling functions with errexit
|
||
|
|
- name: "Functions calling functions with errexit"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
inner() { false; echo "inner should not print"; }
|
||
|
|
outer() { inner; echo "outer should not print"; }
|
||
|
|
outer
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "Nested function call in conditional"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
inner() { false; }
|
||
|
|
outer() { if inner; then echo "then"; else echo "else"; fi; echo "after inner call"; }
|
||
|
|
outer
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
# Complex combinations
|
||
|
|
- name: "if with && and pipeline"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
if true && false | true; then
|
||
|
|
echo "then"
|
||
|
|
else
|
||
|
|
echo "else"
|
||
|
|
fi
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "if with || and pipeline failure"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
if false || true | false; then
|
||
|
|
echo "then"
|
||
|
|
else
|
||
|
|
echo "else"
|
||
|
|
fi
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "Negated pipeline in conditional"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
if ! false | false; then
|
||
|
|
echo "then"
|
||
|
|
else
|
||
|
|
echo "else"
|
||
|
|
fi
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "Command substitution in argument with errexit"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
echo "value: $(false; echo result)"
|
||
|
|
echo "after echo"
|
||
|
|
|
||
|
|
# PIPESTATUS with pipefail
|
||
|
|
- name: "PIPESTATUS with pipefail and multiple failures"
|
||
|
|
stdin: |
|
||
|
|
set -o pipefail
|
||
|
|
(exit 2) | (exit 3) | (exit 0)
|
||
|
|
echo "Exit: $?; PIPESTATUS: ${PIPESTATUS[@]}"
|
||
|
|
|
||
|
|
- name: "PIPESTATUS preserved correctly with pipefail"
|
||
|
|
stdin: |
|
||
|
|
set -o pipefail
|
||
|
|
(exit 0) | (exit 5) | (exit 0)
|
||
|
|
echo "Exit: $?; PIPESTATUS: ${PIPESTATUS[@]}"
|
||
|
|
|
||
|
|
- name: "pipefail in conditional"
|
||
|
|
stdin: |
|
||
|
|
set -o pipefail
|
||
|
|
if false | true; then
|
||
|
|
echo "then"
|
||
|
|
else
|
||
|
|
echo "else"
|
||
|
|
fi
|
||
|
|
echo "Exit: $?"
|
||
|
|
|
||
|
|
# eval with errexit
|
||
|
|
- name: "eval with failing command"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
eval "false"
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "eval with successful command"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
eval "true"
|
||
|
|
echo "after eval"
|
||
|
|
|
||
|
|
- name: "eval with && chain"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
eval "false && true"
|
||
|
|
echo "after eval"
|
||
|
|
|
||
|
|
- name: "eval with || chain"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
eval "false || true"
|
||
|
|
echo "after eval"
|
||
|
|
|
||
|
|
- name: "eval in conditional"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
if eval "false"; then
|
||
|
|
echo "then"
|
||
|
|
else
|
||
|
|
echo "else"
|
||
|
|
fi
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "eval with multiple commands"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
eval "echo first; false; echo should not print"
|
||
|
|
echo "should not print after eval"
|
||
|
|
|
||
|
|
# source/dot with errexit
|
||
|
|
- name: "source script with failing command"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
echo 'echo "in sourced"; false; echo "should not print"' > /tmp/test_source_$$.sh
|
||
|
|
source /tmp/test_source_$$.sh
|
||
|
|
echo "should not print after source"
|
||
|
|
rm -f /tmp/test_source_$$.sh
|
||
|
|
|
||
|
|
- name: "source script with successful commands"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
echo 'echo "in sourced"; true' > /tmp/test_source_$$.sh
|
||
|
|
source /tmp/test_source_$$.sh
|
||
|
|
echo "after source"
|
||
|
|
rm -f /tmp/test_source_$$.sh
|
||
|
|
|
||
|
|
- name: "dot operator with failing command"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
echo 'false' > /tmp/test_dot_$$.sh
|
||
|
|
. /tmp/test_dot_$$.sh
|
||
|
|
echo "should not print"
|
||
|
|
rm -f /tmp/test_dot_$$.sh
|
||
|
|
|
||
|
|
- name: "source in conditional"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
echo 'false' > /tmp/test_source_$$.sh
|
||
|
|
if source /tmp/test_source_$$.sh; then
|
||
|
|
echo "then"
|
||
|
|
else
|
||
|
|
echo "else"
|
||
|
|
fi
|
||
|
|
echo "after"
|
||
|
|
rm -f /tmp/test_source_$$.sh
|
||
|
|
|
||
|
|
# trap DEBUG interaction
|
||
|
|
- name: "trap DEBUG with errexit"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
trap 'echo "DEBUG"' DEBUG
|
||
|
|
echo "first"
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "trap DEBUG in conditional with errexit"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
trap 'echo "DEBUG"' DEBUG
|
||
|
|
if false; then
|
||
|
|
echo "then"
|
||
|
|
else
|
||
|
|
echo "else"
|
||
|
|
fi
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
# BASH_COMMAND with errexit
|
||
|
|
- name: "BASH_COMMAND set during errexit"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
trap 'echo "failed: $BASH_COMMAND"' EXIT
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "BASH_COMMAND in function with errexit"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
trap 'echo "failed: $BASH_COMMAND"' EXIT
|
||
|
|
myfunc() { false; }
|
||
|
|
myfunc
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
# Arithmetic expansion failures
|
||
|
|
- name: "Division by zero in arithmetic expansion"
|
||
|
|
ignore_stderr: true
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
echo "before"
|
||
|
|
result=$((1/0))
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "Division by zero in (( ))"
|
||
|
|
ignore_stderr: true
|
||
|
|
known_failure: true # TODO(arithmetic): Division by zero should trigger errexit
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
echo "before"
|
||
|
|
(( 1/0 ))
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "Division by variable zero"
|
||
|
|
ignore_stderr: true
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
x=0
|
||
|
|
result=$((1/x))
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
# Multiple assignments with one failure
|
||
|
|
- name: "Multiple assignments with middle failure"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
a=$(echo "a") b=$(false) c=$(echo "c")
|
||
|
|
echo "a=$a b=$b c=$c"
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "Multiple assignments all succeed"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
a=$(echo "a") b=$(echo "b") c=$(echo "c")
|
||
|
|
echo "a=$a b=$b c=$c"
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "Multiple assignments first fails"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
a=$(false) b=$(echo "b") c=$(echo "c")
|
||
|
|
echo "a=$a b=$b c=$c"
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
# time keyword with errexit
|
||
|
|
- name: "time with failing command"
|
||
|
|
ignore_stderr: true
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
time false
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "time with successful command"
|
||
|
|
ignore_stderr: true
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
time true
|
||
|
|
echo "after time"
|
||
|
|
|
||
|
|
- name: "time in conditional"
|
||
|
|
ignore_stderr: true
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
if time false; then
|
||
|
|
echo "then"
|
||
|
|
else
|
||
|
|
echo "else"
|
||
|
|
fi
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "time with pipeline"
|
||
|
|
ignore_stderr: true
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
time true | false
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
# Pattern matching failures
|
||
|
|
- name: "Extended test with valid regex"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
var="hello"
|
||
|
|
if [[ $var =~ ^h ]]; then
|
||
|
|
echo "matched"
|
||
|
|
else
|
||
|
|
echo "no match"
|
||
|
|
fi
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "Extended test regex no match"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
var="hello"
|
||
|
|
[[ $var =~ ^x ]] || echo "no match"
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
# Extglob in case patterns
|
||
|
|
- name: "case with extglob pattern"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
shopt -s extglob
|
||
|
|
case "abc" in
|
||
|
|
a*(b)c) echo "matched" ;;
|
||
|
|
*) echo "no match" ;;
|
||
|
|
esac
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "case with extglob no match"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
shopt -s extglob
|
||
|
|
case "xyz" in
|
||
|
|
a*(b)c) echo "matched" ;;
|
||
|
|
esac
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
# Signal handler during errexit (limited - can't easily test INT)
|
||
|
|
- name: "EXIT trap runs before errexit terminates"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
trap 'echo "EXIT trap: $?"' EXIT
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "Multiple traps with errexit"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
trap 'echo "EXIT: $?"' EXIT
|
||
|
|
trap 'echo "ERR: $?"' ERR
|
||
|
|
false
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
# Coproc with errexit
|
||
|
|
- name: "coproc with failing command"
|
||
|
|
known_failure: true # TODO(wait): wait with job specs not implemented
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
coproc { exit 5; }
|
||
|
|
wait $COPROC_PID
|
||
|
|
echo "after coproc wait, status: $?"
|
||
|
|
|
||
|
|
- name: "coproc with successful command"
|
||
|
|
known_failure: true # TODO(wait): wait with job specs not implemented
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
coproc { echo "from coproc"; }
|
||
|
|
cat <&${COPROC[0]}
|
||
|
|
wait $COPROC_PID
|
||
|
|
echo "after coproc"
|
||
|
|
|
||
|
|
- name: "coproc in conditional"
|
||
|
|
known_failure: true # TODO(wait): wait with job specs not implemented
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
coproc { exit 1; }
|
||
|
|
if wait $COPROC_PID; then
|
||
|
|
echo "then"
|
||
|
|
else
|
||
|
|
echo "else"
|
||
|
|
fi
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "coproc with name and brace group"
|
||
|
|
stdin: |
|
||
|
|
f() { coproc MYCOPROC { echo hello; }; }
|
||
|
|
f
|
||
|
|
|
||
|
|
# Additional edge cases
|
||
|
|
- name: "Subshell in assignment with errexit"
|
||
|
|
known_failure: true # TODO(arithmetic): $(( exit 5 )) is parsed differently from bash
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
var=$(( exit 5 ))
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "Arithmetic in condition of && chain"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
(( 0 )) && echo "matched" || echo "not matched"
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "Nested eval with errexit"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
eval 'eval "false"'
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "Command group with errexit"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
{ echo "first"; false; echo "should not print"; }
|
||
|
|
echo "should not print after group"
|
||
|
|
|
||
|
|
- name: "Empty command with errexit"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
:
|
||
|
|
echo "after colon"
|
||
|
|
|
||
|
|
- name: "true command with errexit"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
true
|
||
|
|
echo "after true"
|
||
|
|
|
||
|
|
- name: "break in errexit context"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
for i in 1 2 3; do
|
||
|
|
if [ $i -eq 2 ]; then
|
||
|
|
break
|
||
|
|
fi
|
||
|
|
echo "i=$i"
|
||
|
|
done
|
||
|
|
echo "after loop"
|
||
|
|
|
||
|
|
- name: "continue in errexit context"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
for i in 1 2 3; do
|
||
|
|
if [ $i -eq 2 ]; then
|
||
|
|
continue
|
||
|
|
fi
|
||
|
|
echo "i=$i"
|
||
|
|
done
|
||
|
|
echo "after loop"
|
||
|
|
|
||
|
|
- name: "Complex nested structure"
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
outer() {
|
||
|
|
inner() {
|
||
|
|
if false; then
|
||
|
|
echo "inner then"
|
||
|
|
else
|
||
|
|
echo "inner else"
|
||
|
|
fi
|
||
|
|
false
|
||
|
|
echo "should not print in inner"
|
||
|
|
}
|
||
|
|
inner
|
||
|
|
echo "should not print in outer"
|
||
|
|
}
|
||
|
|
outer
|
||
|
|
echo "should not print"
|
||
|
|
|
||
|
|
- name: "with -u"
|
||
|
|
ignore_stderr: true
|
||
|
|
stdin: |
|
||
|
|
set -eu
|
||
|
|
echo "before"
|
||
|
|
x=$unset
|
||
|
|
echo "after"
|
||
|
|
|
||
|
|
- name: "syntax error"
|
||
|
|
ignore_stderr: true
|
||
|
|
stdin: |
|
||
|
|
set -e
|
||
|
|
echo "before"
|
||
|
|
if false; then echo hi; done
|
||
|
|
echo "after"
|