Как добиться раннего выхода из блока кода в скрипте bash (по аналогии с `последней директивой Perl `)?

Как насчет удаления записей из массива поиска по мере их сопоставления, а затем вывода того, что осталось в конце?

$ awk 'NR==FNR {a[$1]; next} 
  $1 in a {print; delete a[$1]} 
  END {for (i in a) print i, "10 20"}
' ref.txt file.txt
Doc_A 123 abc
Doc_B 123 abc
Doc_C 123 abc
Doc_D 10 20
Doc_E 10 20
Doc_F 10 20

(Обратите внимание, что awk не гарантирует порядок обхода массива -, если это проблема.)

Пояснение

В то время как NR==FNRмы обрабатываем первый именованный файл(ref.txt):мы создаем запись массива с его первым (в этом случае только полем )в качестве его индекса, а затем переходим к записи next. Нам не нужно присваивать значение элементу массива.

В противном случае мы обрабатываем второй именованный файл(file.txt). Мы проверяем, имеет ли его первый столбец совпадение с массивом a, который мы создали из эталонного файла, и печатаем запись $0, если оно есть. Затем удаляем запись.

Удаление служит двум целям: :оно «уникализирует» совпадение, потому что в следующий раз, когда мы проверим $1 in aна то же самое $1, ответ будет ложным. Это также означает, что после того, как все строки file.txtбыли обработаны, любые оставшиеся элементы в aне были сопоставлены -, мы можем распечатать их в вашем «фиксированном» формате в блоке END.

0
27.09.2020, 23:28
3 ответа

Мне неизвестен способ сделать то, что вам нужно, в Bash (, кроме опций, которые вы уже определили ).

Если бы я пытался сделать то, что вы хотите, я бы, вероятно, сделал что-то вроде:

#!/bin/bash

overall_status=failed
value=$1

if   (( value > 0 )); then echo "value > 0"
elif (( value > 1 )); then echo "value > 1"
elif (( value > 2 )); then echo "value > 2"
elif (( value > 3 )); then echo "value > 3"
else overall_status=ok
fi

if [[ "$overall_status" != ok ]]; then
    echo 'EARLY EXIT' >&2
    exit 1
fi
3
18.03.2021, 23:02

Простой способ раннего выхода из группы команд — это и список с использованием &&, который прерывается при первом сбое, что является короткой заменой операторов ifили case.. Замена фиктивного цикла while в вашем примере на этот:

(( value > 0 )) && echo "$value > 0" &&
(( value > 1 )) && echo "$value > 1" &&
(( value > 2 )) && echo "$value > 2" &&
(( value > 3 )) && echo "$value > 3" &&
overall_status=ok

Или аналогично вашей анонимной функции zsh, почему у вас нет именованной функции bash.

#!/bin/bash

arg=$1

function f() {
    value=$1
    (( value > 0 )) && echo "$value > 0" || return 1
    (( value > 1 )) && echo "$value > 1" || return 1
    (( value > 2 )) && echo "$value > 2" || return 1
    (( value > 3 )) && echo "$value > 3" || return 1
    return 0
}

if f arg; then
    exit 0
else
    echo 'EARLY EXIT' >&2
    exit 1
fi
3
18.03.2021, 23:02

Еще варианты:

  • подоболочка и используйте exit, чтобы выйти из нее:

    (
     ... || exit # failure
     ... && exit # success
    ) || die 'subshell failed'
    
  • поместите свой код в условную часть цикла:

    while
     ... || break
     ... && break
    do break; done
    

    Обратите внимание, однако, что статус выхода из цикла всегда будет равен 0.

    При подходе с циклом forвы можете использовать ! breakдля выхода из цикла со статусом отказа (, но не с помощью pdksh или его производных):

    for once in total; do
     ... || ! break
     ... && continue # same as break
    done
    

    Обратите внимание, что при приближении к петле вы можете выйти из более чем одной охватывающей петли с помощью break 2, break 3...

  • источник здесь -документ:

    . /dev/fd/3 3<< 'EOF'
    ... || return
    ... && return
    EOF
    
2
18.03.2021, 23:02

Теги

Похожие вопросы