有这样的方法吗
int a = (b == 5) ? c : d;
使用Bash ?
有这样的方法吗
int a = (b == 5) ? c : d;
使用Bash ?
当前回答
上面的答案[[$b = 5]] && a="$c" || a="$d"应该只在你确定&&之后没有错误的情况下使用,否则它将错误地执行||之后的部分。
为了解决这个问题,我写了一个三元函数,它的行为应该,它甚至使用?和:操作符:
编辑-新的解决方案
这是我的新解决方案,不使用$IFS或ev(a/i)l。
function executeCmds()
{
declare s s1 s2 i j k
declare -A cmdParts
declare pIFS=$IFS
IFS=$'\n'
declare results=($(echo "$1" | grep -oP '{ .*? }'))
IFS=$pIFS
s="$1"
for ((i=0; i < ${#results[@]}; i++)); do
s="${s/${results[$i]}/'\0'}"
results[$i]="${results[$i]:2:${#results[$i]}-3}"
results[$i]=$(echo ${results[$i]%%";"*})
done
s="$s&&"
let cmdParts[t]=0
while :; do
i=${cmdParts[t]}
let cmdParts[$i,t]=0
s1="${s%%"&&"*}||"
while :; do
j=${cmdParts[$i,t]}
let cmdParts[$i,$j,t]=0
s2="${s1%%"||"*};"
while :; do
cmdParts[$i,$j,${cmdParts[$i,$j,t]}]=$(echo ${s2%%";"*})
s2=${s2#*";"}
let cmdParts[$i,$j,t]++
[[ $s2 ]] && continue
break
done
s1=${s1#*"||"}
let cmdParts[$i,t]++
[[ $s1 ]] && continue
break
done
let cmdParts[t]++
s=${s#*"&&"}
[[ $s ]] && continue
break
done
declare lastError=0
declare skipNext=false
for ((i=0; i < ${cmdParts[t]}; i++ )) ; do
let j=0
while :; do
let k=0
while :; do
if $skipNext; then
skipNext=false
else
if [[ "${cmdParts[$i,$j,$k]}" == "\0" ]]; then
executeCmds "${results[0]}" && lastError=0 || lastError=1
results=("${results[@]:1}")
elif [[ "${cmdParts[$i,$j,$k]:0:1}" == "!" || "${cmdParts[$i,$j,$k]:0:1}" == "-" ]]; then
[ ${cmdParts[$i,$j,$k]} ] && lastError=0 || lastError=1
else
${cmdParts[$i,$j,$k]}
lastError=$?
fi
if (( k+1 < cmdParts[$i,$j,t] )); then
skipNext=false
elif (( j+1 < cmdParts[$i,t] )); then
(( lastError==0 )) && skipNext=true || skipNext=false
elif (( i+1 < cmdParts[t] )); then
(( lastError==0 )) && skipNext=false || skipNext=true
fi
fi
let k++
[[ $k<${cmdParts[$i,$j,t]} ]] || break
done
let j++
[[ $j<${cmdParts[$i,t]} ]] || break
done
done
return $lastError
}
function t()
{
declare commands="$@"
find="$(echo ?)"
replace='?'
commands="${commands/$find/$replace}"
readarray -d '?' -t statement <<< "$commands"
condition=${statement[0]}
readarray -d ':' -t statement <<< "${statement[1]}"
success="${statement[0]}"
failure="${statement[1]}"
executeCmds "$condition" || { executeCmds "$failure"; return; }
executeCmds "$success"
}
executeCmds将每个命令单独分开,除了由于&&和||操作符而应该跳过的命令。当命令以!开头时,它使用[]。或者一面旗帜。
向它传递命令有两种方式:
传递单个命令时不加引号,但一定要引用;、&&和||操作符。
t ls / ? ls qqq '||' echo aaa : echo bbb '&&' ls qq
传递所有引用的命令:
t 'ls /a ? ls qqq || echo aaa : echo bbb && ls qq'
注意,我发现没有办法将&&和||操作符作为不带引号的参数传递,因为它们是函数名和别名的非法字符,我也没有办法覆盖bash操作符。
旧的解决方案-使用ev(a/i)l
function t()
{
pIFS=$IFS
IFS="?"
read condition success <<< "$@"
IFS=":"
read success failure <<< "$success"
IFS=$pIFS
eval "$condition" || { eval "$failure" ; return; }
eval "$success"
}
t ls / ? ls qqq '||' echo aaa : echo bbb '&&' ls qq
t 'ls /a ? ls qqq || echo aaa : echo bbb && ls qq'
其他回答
如果条件仅仅是检查是否设置了变量,甚至还有更短的形式:
a=${VAR:-20}
如果VAR已设置,则会将VAR值赋给a,否则将为其赋值默认值20——这也可以是表达式的结果。
这种方法在技术上称为“参数展开”。
上面的答案[[$b = 5]] && a="$c" || a="$d"应该只在你确定&&之后没有错误的情况下使用,否则它将错误地执行||之后的部分。
为了解决这个问题,我写了一个三元函数,它的行为应该,它甚至使用?和:操作符:
编辑-新的解决方案
这是我的新解决方案,不使用$IFS或ev(a/i)l。
function executeCmds()
{
declare s s1 s2 i j k
declare -A cmdParts
declare pIFS=$IFS
IFS=$'\n'
declare results=($(echo "$1" | grep -oP '{ .*? }'))
IFS=$pIFS
s="$1"
for ((i=0; i < ${#results[@]}; i++)); do
s="${s/${results[$i]}/'\0'}"
results[$i]="${results[$i]:2:${#results[$i]}-3}"
results[$i]=$(echo ${results[$i]%%";"*})
done
s="$s&&"
let cmdParts[t]=0
while :; do
i=${cmdParts[t]}
let cmdParts[$i,t]=0
s1="${s%%"&&"*}||"
while :; do
j=${cmdParts[$i,t]}
let cmdParts[$i,$j,t]=0
s2="${s1%%"||"*};"
while :; do
cmdParts[$i,$j,${cmdParts[$i,$j,t]}]=$(echo ${s2%%";"*})
s2=${s2#*";"}
let cmdParts[$i,$j,t]++
[[ $s2 ]] && continue
break
done
s1=${s1#*"||"}
let cmdParts[$i,t]++
[[ $s1 ]] && continue
break
done
let cmdParts[t]++
s=${s#*"&&"}
[[ $s ]] && continue
break
done
declare lastError=0
declare skipNext=false
for ((i=0; i < ${cmdParts[t]}; i++ )) ; do
let j=0
while :; do
let k=0
while :; do
if $skipNext; then
skipNext=false
else
if [[ "${cmdParts[$i,$j,$k]}" == "\0" ]]; then
executeCmds "${results[0]}" && lastError=0 || lastError=1
results=("${results[@]:1}")
elif [[ "${cmdParts[$i,$j,$k]:0:1}" == "!" || "${cmdParts[$i,$j,$k]:0:1}" == "-" ]]; then
[ ${cmdParts[$i,$j,$k]} ] && lastError=0 || lastError=1
else
${cmdParts[$i,$j,$k]}
lastError=$?
fi
if (( k+1 < cmdParts[$i,$j,t] )); then
skipNext=false
elif (( j+1 < cmdParts[$i,t] )); then
(( lastError==0 )) && skipNext=true || skipNext=false
elif (( i+1 < cmdParts[t] )); then
(( lastError==0 )) && skipNext=false || skipNext=true
fi
fi
let k++
[[ $k<${cmdParts[$i,$j,t]} ]] || break
done
let j++
[[ $j<${cmdParts[$i,t]} ]] || break
done
done
return $lastError
}
function t()
{
declare commands="$@"
find="$(echo ?)"
replace='?'
commands="${commands/$find/$replace}"
readarray -d '?' -t statement <<< "$commands"
condition=${statement[0]}
readarray -d ':' -t statement <<< "${statement[1]}"
success="${statement[0]}"
failure="${statement[1]}"
executeCmds "$condition" || { executeCmds "$failure"; return; }
executeCmds "$success"
}
executeCmds将每个命令单独分开,除了由于&&和||操作符而应该跳过的命令。当命令以!开头时,它使用[]。或者一面旗帜。
向它传递命令有两种方式:
传递单个命令时不加引号,但一定要引用;、&&和||操作符。
t ls / ? ls qqq '||' echo aaa : echo bbb '&&' ls qq
传递所有引用的命令:
t 'ls /a ? ls qqq || echo aaa : echo bbb && ls qq'
注意,我发现没有办法将&&和||操作符作为不带引号的参数传递,因为它们是函数名和别名的非法字符,我也没有办法覆盖bash操作符。
旧的解决方案-使用ev(a/i)l
function t()
{
pIFS=$IFS
IFS="?"
read condition success <<< "$@"
IFS=":"
read success failure <<< "$success"
IFS=$pIFS
eval "$condition" || { eval "$failure" ; return; }
eval "$success"
}
t ls / ? ls qqq '||' echo aaa : echo bbb '&&' ls qq
t 'ls /a ? ls qqq || echo aaa : echo bbb && ls qq'
简单的三元
brew list | grep -q bat && echo 'yes' || echo 'no'
此示例将确定您是否使用自制程序安装bat
如果是,你会看到"是"
如果是false,你会看到"no"
我在这里添加了-q来抑制grepped字符串输出,所以你只能看到“yes”或“no”
真正的模式是这样的
doSomethingAndCheckTruth && echo 'yes' || echo 'no'
用bash和zsh测试
代码:
a=$([ "$b" == 5 ] && echo "$c" || echo "$d")
(ping -c1 localhost&>/dev/null) && { echo "true"; } || { echo "false"; }