Подстановка вложенных команд не останавливает скрипт в случае сбоя, даже если установлены -e и shopt -s inherit_errexit

GNU AWK

Вот тестовый прогон со слегка измененным входным файлом:

bash-4.3$ $ awk '{v=sprintf("%s_%s",$1,$NF); if ( ! a[v]) print;   a[v]++;   }' input.txt 
bash: $: command not found
bash-4.3$ awk '{v=sprintf("%s_%s",$1,$NF); if ( ! a[v]) print;   a[v]++;   }' input.txt 
AAAAA stuff in between BBBBB
AA stuff AAABBBBB
AAAAA more stuff in the middle CCCCCC

bash-4.3$ cat input.txt
AAAAA stuff in between BBBBB
AA stuff AAABBBBB
AAAAA more stuff in the middle CCCCCC
AAAAA even more cool stuff BBBBB
AAAAA extra line CCCCCC

Как это работает:

  • Ключевой момент :мы создаем массив пар ключей -значений и печатаем в зависимости от того, есть ли у нас уже элемент массива для этой пары значений ключа -
  • Ключ
  • строится с помощью v=sprintf("%s_%s",$1,$NF), где $NF— последнее поле в строке; например, для строк 1 и 3 ключ будет AAAAABBBBB. Значение — это целое число, которое увеличивается каждый раз, когда мы находим совпадение.
  • Переменная
  • vи соответствующая проверка if (!a[v]) printвыполняются для каждой строки, печать выполняется только в том случае, если значение не найдено в массиве.
  • a[v]++выполняется в каждой строке независимо от того, печатали мы или нет

Как указал Сандип в комментариях, этот же подход можно упростить до:

bash-4.3$ awk '!seen[$1"_"$NF]++' input.txt
AAAAA stuff in between BBBBB
AA stuff AAABBBBB
AAAAA more stuff in the middle CCCCCC
2
16.09.2019, 11:04
1 ответ

Основываясь на ответе (, который, похоже, был удален )и экспериментах, которые я провел, я пришел к выводу, что эту (подстановку вложенных команд )следует рассматривать только как «плохую практику» или в лучшем случае «очень громоздкий».

Лучшее, что я мог сделать, это

#!/bin/bash
set -eu -o pipefail -E
shopt -s inherit_errexit

function func1() {
  [[ $? == 0 ]]; return 1 # The boilerplate line
  local arg="${1}"
  echo "(func1)This line shouldn't be reached:arg='${arg}': '${?}'" >&2
}

function func2() {
  echo "value from func2"
  return 1
}

var="$(func1 "$(func2)")" # The line
echo "main:This line shouldn't be reached:var='${var}':'${?}'" >&2

Это приводит к ожидаемому выходному (пустому )и не-нулевому (1 )коду выхода. Хитрость заключается в том, чтобы проверить, является ли $?0в первой строке определения функции. И эта (шаблонная строка )должна быть вставлена ​​для каждого определения функции, которое повторно используется в «подстановке вложенных команд». Если вы хотите использовать синтаксис «вложенной подстановки команд», не беспокоясь, вам нужно ознакомиться с вставкой шаблона каждый раз, когда вы создаете новую функцию.

И действительно ли «Шаблонная линия» безобидна? Видимо, да, верю. Поскольку, если вы set -eu, в любом случае при обнаружении сбоя ожидается немедленный аборт. Но я плохо разбираюсь в программировании на bash и, возможно, упустил какую-то потенциальную ловушку. Очень хотелось бы узнать мнения более опытных людей. Заранее спасибо.

0
27.01.2020, 22:24

Теги

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