codememo

Bash의 3진 연산자(?:)

tipmemo 2023. 4. 23. 10:28
반응형

Bash의 3진 연산자(?:)

이런 거 할 수 있는 건가요?

int a = (b == 5) ? c : d;

Bash 사용?

연산자 ''''? :이에요.if/else

case "$b" in
 5) a=$c ;;
 *) a=$d ;;
esac

또는

 [[ $b = 5 ]] && a="$c" || a="$d"

코드:

a=$([ "$b" == 5 ] && echo "$c" || echo "$d")

조건이 단순히 변수가 설정되어 있는지 확인하는 경우, 보다 짧은 형식이 있습니다.

a=${VAR:-20}

a의 의 값VARVAR 「」가 됩니다.20에 의한 일 수도 있습니다이렇게 하다.

이 접근방식은 기술적으로 "파라미터 확장"이라고 불립니다.

if [[ $b -eq 5 ]]; then a="$c"; else a="$d"; fi

cond && op1 || op2오류가 . 즉, 만약 '있다'가 '있다.op1상태가 .「 0 」 。op2는 사일런트 결과가 에러는 에러나 에러에 잡히지 .-e이은 드모모 safe 합니다. 그러니까, 그 표현은 안전합니다.op1 실패하지 않습니다).:,true(분할이나 OS 콜 등) 실패할 가능성이 있는 조작이 없는 내장 또는 변수 할당의 경우.

해 주세요.""이 모두1개의 으로 변환되지 않도록 .모든 공백이 단일 공간으로 변환되지 않도록 합니다.

2개의 잘못 하는 것을 방지할 수고를 할 수 .$btest " 산예 ( " )-z의 회피책; 의 ; 의 회피책.[[ "x$b" == "xyes" ]문자열 비교에만 사용할 수 있으며, 견적 요건도 완화됩니다.

(( a = b==5 ? c : d )) # string + numeric
[ $b == 5 ] && { a=$c; true; } || a=$d

이렇게 하면 &&와 | 사이의 코드가 고장났을 때 실수로 || 뒤에 있는 부품이 실행되지 않게 됩니다.

3진 연산자의 셸 스크립팅에서는 다음 3가지 방법을 사용할 수 있습니다.

    [ $numVar == numVal ] && resVar="Yop" || resVar="Nop"

Or

    resVar=$([ $numVar == numVal ] && echo "Yop" || echo "Nop")

Or

    (( numVar == numVal ? (resVar=1) : (resVar=0) ))

업데이트: 아래 실행 준비 예제를 사용하여 문자열 계산에 대한 답변을 확장합니다.이것은 위에서 언급한 두 번째 형식을 사용하고 있습니다.

$ strVar='abc';resVar=$([[ $strVar == 'abc' ]] && echo "Yop" || echo "Nop");echo $resVar
Yop
$ strVar='aaa';resVar=$([[ $strVar == 'abc' ]] && echo "Yop" || echo "Nop");echo $resVar
Nop

let 명령어는 필요한 대부분의 기본 연산자를 지원합니다.

let a=b==5?c:d;

기본적으로 이것은 변수를 할당하는 경우에만 작동하며 다른 명령을 실행할 수 없습니다.

다음 옵션에서는 할당하는 변수를 한 번만 지정하면 됩니다.할당하는 변수가 문자열이든 숫자든 상관없습니다.

VARIABLE=`[ test ] && echo VALUE_A || echo VALUE_B`

생각일 뿐이야.:)

bash의 3진 조건에도 매우 비슷하지만 간단한 구문이 있습니다.

a=$(( b == 5 ? 123 : 321  ))

다음 사항이 내 사용 사례에 적합한 것 같습니다.

$ tern 1 YES NO                                                                             
YES
    
$ tern 0 YES NO                                                                             
NO
    
$ tern 52 YES NO                                                                            
YES
    
$ tern 52 YES NO 52                                                                         
NO

다음과 같은 스크립트로 사용할 수 있습니다.

RESULT=$(tern 1 YES NO)
echo "The result is $RESULT"

제비꽃

#!/usr/bin/env bash

function show_help()
{
  ME=$(basename "$0")
  IT=$(cat <<EOF

  Returns a ternary result

  usage: BOOLEAN VALUE_IF_TRUE VALUE_IF_FALSE
  
  e.g. 
  
  # YES
  $ME 1 YES NO                                

  # NO
  $ME 0 YES NO

  # NO
  $ME "" YES NO

  # YES
  $ME "STRING THAT ISNT BLANK OR 0" YES NO

  # INFO contains NO
  INFO=\$($ME 0 YES NO)
EOF
)
  echo "$IT"
  echo
  exit
}

if [ "$1" = "help" ] || [ "$1" = '?' ] || [ "$1" = "--help" ] || [ "$1" = "h" ]; then
  show_help
fi
if [ -z "$3" ]
then
  show_help
fi

# Set a default value for what is "false" -> 0
FALSE_VALUE=${4:-0}

function main
{
  if [ "$1" == "$FALSE_VALUE" ] || [ "$1" = '' ]; then
    echo $3
    exit;
  fi;

  echo $2
}

main "$1" "$2" "$3"

여기 일반적인 해결책이 있습니다.

  • 스트링 테스트에서도 동작합니다.
  • 다소 표현처럼 느껴진다
  • 상태가 실패했을 때의 미묘한 부작용을 회피하다

수치 비교 테스트

a=$(if [ "$b" -eq 5 ]; then echo "$c"; else echo "$d"; fi)

문자열 비교 테스트

a=$(if [ "$b" = "5" ]; then echo "$c"; else echo "$d"; fi)
(ping -c1 localhost&>/dev/null) && { echo "true"; } || {  echo "false"; }

유사한 구문을 원하는 경우 사용할 수 있습니다.

a=$(( $((b==5)) ? c : d ))

몇몇 사람들은 이미 좋은 대안을 제시했습니다.한 을 얻고 '어느 정도인지 아닌지는 요.?.

이를 통해 다음 구문을 사용할 수 있습니다.

[[ $x -eq 1 ]]; ? ./script1 : ./script2
# or
? '[[ $x -eq 1 ]]' ./script1 : ./script2

경우든, 「」는:는 옵션입니다.공백이이는 ''로 되기 때문입니다. 값은 따옴표로 묶어야 합니다.eval.

경우,<then> ★★★★★★★★★★★★★★★★★」<else>명령어가 함수는echo절한값값 값값값다다

./script; ? Success! : "Failure :("

함수

?() {
  local lastRet=$?
  if [[ $1 == --help || $1 == -? ]]; then
    echo $'\e[37;1mUsage:\e[0m
  ? [<condition>] <then> [:] <else>

If \e[37;1m<then>\e[0m and/or \e[37;1m<else>\e[0m are not valid commands, then their values are
printed to stdOut, otherwise they are executed.  If \e[37;1m<condition>\e[0m is not
specified, evaluates the return code ($?) of the previous statement.

\e[37;1mExamples:\e[0m
  myVar=$(? "[[ $x -eq 1 ]] foo bar)
  \e[32;2m# myVar is set to "foo" if x is 1, else it is set to "bar"\e[0m

  ? "[[ $x = *foo* ]] "cat hello.txt" : "cat goodbye.txt"
  \e[32;2m# runs cat on "hello.txt" if x contains the word "foo", else runs cat on
  # "goodbye.txt"\e[0m

  ? "[[ $x -eq 1 ]] "./script1" "./script2"; ? "Succeeded!" "Failed :("
  \e[32;2m# If x = 1, runs script1, else script2.  If the run script succeeds, prints
  # "Succeeded!", else prints "failed".\e[0m'
    return
  elif ! [[ $# -eq 2 || $# -eq 3 || $# -eq 4 && $3 == ':' ]]; then
    1>&2 echo $'\e[37;1m?\e[0m requires 2 to 4 arguments

\e[37;1mUsage\e[0m: ? [<condition>] <then> [:] <else>
Run \e[37;1m? --help\e[0m for more details'
    return 1
  fi

  local cmd

  if [[ $# -eq 2 || $# -eq 3 && $2 == ':' ]]; then
    cmd="[[ $lastRet -eq 0 ]]"
  else
    cmd="$1"
    shift
  fi

  if [[ $2 == ':' ]]; then
    eval "set -- '$1' '$3'"
  fi

  local result=$(eval "$cmd" && echo "$1" || echo "$2")
  if command -v ${result[0]} &> /dev/null; then
    eval "${result[@]}"
  else
    echo "${result[@]}"
  fi
}

물론 스크립트를 짧게 하려면 도움말텍스트를 삭제할 수 있습니다.

편집: 몰랐습니다.?는, 파일명의 플레이스 홀더 문자로서 기능합니다.「」와 같이, 임의의 하는 것이 ,*딱글자와 합니다.따라서 작업 디렉토리에 1글자 파일이 있는 경우 bash는 명령어로 파일 이름을 실행하려고 합니다.★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★는 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★command "?" ...args네, 네, 네, 네, 네, 네, 네, 네, 네, 네, 네.

가장 단순한 삼진법

brew list | grep -q bat && echo 'yes' || echo 'no'

에서는 집을 했는지 여부를 할 수 있습니다.brewbat 아직 아니다

참일 경우 "예"가 표시됩니다.

거짓일 경우 "아니오"라고 표시됩니다.

는 가했 the the the를 추가했다.-qgrep에는 yes nostring만

정말 당신이 찾는 패턴은 이것입니다.

doSomethingAndCheckTruth && echo 'yes' || echo 'no'

「 」로 테스트 .bash ★★★★★★★★★★★★★★★★★」zsh

몇 가지 옵션은 다음과 같습니다.

1-한 줄에 다른 것을 사용할 경우 가능합니다.

if [[ "$2" == "raiz" ]] || [[ "$2" == '.' ]]; then pasta=''; else pasta="$2"; fi

2- 다음과 같은 함수를 작성합니다.

 # Once upon a time, there was an 'iif' function in MS VB ...

function iif(){
  # Echoes $2 if 1,banana,true,etc and $3 if false,null,0,''
  case $1 in ''|false|FALSE|null|NULL|0) echo $3;;*) echo $2;;esac
}

이렇게 내부 스크립트를 사용하다

result=`iif "$expr" 'yes' 'no'`

# or even interpolating:
result=`iif "$expr" "positive" "negative, because $1 is not true"` 

3- 사례의 답변에서 영감을 받아 보다 유연하고 한 줄씩 사용할 수 있습니다.

 case "$expr" in ''|false|FALSE|null|NULL|0) echo "no...$expr";;*) echo "yep $expr";;esac

 # Expression can be something like:     
   expr=`expr "$var1" '>' "$var2"`

이것은 Vladimir의 훌륭한 대답과 매우 유사하다."ternary"가 "true, string, false, empty"의 대소문자인 경우 다음 작업을 수행할 수 있습니다.

$ c="it was five"
$ b=3
$ a="$([[ $b -eq 5 ]] && echo "$c")"
$ echo $a

$ b=5
$ a="$([[ $b -eq 5 ]] && echo "$c")"
$ echo $a
it was five

배열을 사용하는 문자열 지향 대체 방법:

spec=(IGNORE REPLACE)
for p in {13..15}; do
  echo "$p: ${spec[p==14]}";
done

출력:

13: IGNORE
14: REPLACE
15: IGNORE

int a = (b == 5) ? c : d;

다음과 같이 적어주세요.

b=5
c=1
d=2
let a="(b==5)?c:d"

echo $a # 1

b=6;
c=1;
d=2;
let a="(b==5)?c:d"

echo $a # 2

expression은 $((식))에 상당합니다.

2개의 답변이 더 있습니다.

여기 이것에 대해 생각하는 몇 가지 방법이 있다.

bash 정수 변수

또한 Dutch, Vladimir 및 ghostdog74정수가 달린 bash에 관한 질문이기 때문에 답변을 수정합니다.

이런 거 할 수 있는 건가요?

int a = (b == 5) ? c : d;

bash 아래에 있는 정수를 사용하는 적절한 방법이 있습니다.

declare -i b=' RANDOM % 3 + 4 ' c=100 d=50 a='  b == 5 ? c : d '; echo $b '-->' $a

이 명령어의 출력 행은 다음 중 하나로 해야 합니다.

4 --> 50
5 --> 100
6 --> 50

물론 변수의 정수 유형을 선언하는 작업은 한 번 수행합니다.

declare -i a b c d
c=100 d=50 b=RANDOM%3+4
a=' b == 5 ? c : d '
echo $a $b
100 5
b=12 a=b==5?c:d
echo $a $b
50 12

탈선:산술 함수로 문자열 사용:

mathString=' b == 5 ? c : d '
b=5 a=$mathString
echo $a $b
100 5

b=1 a=$mathString 
echo $a $b
50 1

매개 변수 확장 및 간접 기반

Brad Parks와 druid62답변에 따라 정수에 국한되지 않는 방법을 소개합니다.

c=50 d=100 ar=([5]=c)
read -p 'Enter B: ' b
e=${ar[b]:-d};echo ${!e}
  • 한다면b==5,그리고나서ar[b]c간접적으로도c50.
  • 또 다른ar[any value other than 5]파라미터의 전개는 디폴트로 비어 있습니다.d여기서 indirection은100.

정수 대신 어레이를 사용한 동일한 데모

ternArrayDemo(){
    local -a c=(foo bar) d=(foo bar baz) e=(empty) ar=([5]=c [2]=d)
    local b=${ar[$1]:-e}
    b+=[@]      # For array indirection
    printf ' - %s\n' "${!b}"
}

그리고나서

ternArrayDemo 0
 - empty
ternArrayDemo 2 
 - foo
 - bar
 - baz
ternArrayDemo 4
 - empty
ternArrayDemo 5
 - foo
 - bar
ternArrayDemo 6
 - empty

또는 어소시에이트 어레이 사용

ternAssocArrayDemo(){
     local -a c=(foo bar) d=(foo bar baz) e=(empty)
     local -A ar=([foo]=c[@] [bar]=d[@] [baz]=d[-1])
     local b=${ar[$1]:-e[@]}
     printf ' - %s\n' "${!b}"
}

그리고나서

ternAssocArrayDemo hello
 - empty
ternAssocArrayDemo foo
 - foo
 - bar
ternAssocArrayDemo bar
 - foo
 - bar
 - baz
ternAssocArrayDemo baz
 - baz

톱답변[[ $b = 5 ]] && a="$c" || a="$d"에러가 발생하지 않는 것이 확실한 경우에만 사용해 주세요.&&, 그렇지 않으면, 그 후에 부품이 잘못 배출됩니다.||.

그 문제를 해결하기 위해 나는 그것이 해야 할 대로 동작하는 삼원 함수를 썼고 그것은 심지어 그것을 사용한다.? ★★★★★★★★★★★★★★★★★」:★★★★★★★★★★★★★★★★★★:

편집 - 새로운 솔루션

기여사 that that that that that 를 사용하지 않는 새로운 해결책이 있습니다.$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는, 「따라서 가 있는 각를 개별적으로 .&& ★★★★★★★★★★★★★★★★★」||오퍼레이터.사용하다[]가 「명령어」로 !또는 깃발입니다.

명령어를 전달하려면 다음 두 가지 방법이 있습니다.

  1. 로 묶지 만, 따옴표로 .;,&& , , , , 입니다.||오퍼레이터.
t ls / ? ls qqq '||' echo aaa : echo bbb '&&' ls qq
  1. 인용된 모든 명령어를 전달합니다.
t 'ls /a ? ls qqq || echo aaa : echo bbb && ls qq'

NB 나는 들어갈 방법을 찾지 못했다.&& ★★★★★★★★★★★★★★★★★」||함수 이름과 별칭에 대한 잘못된 문자이므로 따옴표가 없는 매개 변수로서 연산자를 사용할 수 없습니다.

기존 솔루션 - 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'

이러한 접근방식은 어떻습니까?

# any your function
function check () {
    echo 'checking...';

    # Change the following to 'true' to emulate a successful execution.
    # Note: You can replace check function with any function you wish.
    # Be aware in linux false and true are funcitons themselves. see 'help false' for instance.
    false; 
}

# double check pattern
check && echo 'update' \
    || check || echo 'create'; 

RxJs(필터 파이프 등)에서 조건부 문이 어떻게 작동하는지 확인합니다.네, 코드 복제이지만 제 관점에서는 좀 더 기능적인 접근법입니다.

언급URL : https://stackoverflow.com/questions/3953645/ternary-operator-in-bash

반응형