set -o pipefail errexit
действительно предотвращает выполнение последующих команд, но это вам не помогает, потому что вы не пытаетесь предотвратить выполнение следующей команды. В трубопроводе производитель | Команды потребителя
, производителя
и потребителя
выполняются параллельно . Вы не можете предотвратить запуск потребителя
в случае отказа производителя
, потому что, если не считать случайного совпадения времени, он уже запустился.
Если возможны только две возможности: « потребитель
преуспевает и производит непустой вывод» и « потребитель
терпит неудачу и не производит никакого вывода», вы можете использовать ifne
] из moreutils Джои Хесса .
producer | ifne consumer
Я не думаю, что это сработает в вашем случае - совпадения строк могут не оказаться (ложноотрицательные, и вы получите устаревшие данные), соединение с базой данных может быть потеряно посередине (ложное срабатывание и получить усеченные данные).
Если вам нужно узнать, преуспел ли производитель, вам нужно дождаться его завершения, прежде чем запускать потребителя. А поскольку потребителя еще нет, нужно что-то сохранить вывод.
Если вывод не содержит нулевых байтов и не слишком велик, вы можете сохранить его в переменной оболочки.
output=$(producer); producer_status=$?
if [ $producer_status -ne 0 ]; then
echo >&2 "Producer failed with status $producer_status"
exit $producer_status
fi
printf '%s\n' "$output" | consumer
В ksh93, bash или zsh эта последняя строка может быть упрощена до consumer .
Обратите внимание, что подстановка команд удаляет завершающие символы новой строки. Если уместны завершающие пустые строки, обходной путь состоит в том, чтобы изменить первую строку на
output=$(producer; echo a); producer_status=$?; output=${output%?}
. Если вывод потенциально слишком велик или может содержать нулевые байты, сохраните его во временном файле.
Это больше похоже на код -решение проблемы гольфа/фрика:
xargs -L1 -I{} echo '; {}' <./test.txt | \
xargs -n1 | \
uniq | \
xargs | \
sed -e 's/; /\n/g' -e 's/ \+/\t/g'
Но он избегает использования циклов и всех других тяжелых механизмов, которые можно увидеть в других ответах.
Он также основан на предположении, что ваши данные не содержат символ ;
.
sed -re 's/\s+$//; s/(\t[^\t]+)\1+$/\1/'
(s/\s+$//
избавляется от завершающего белого пробела -, как в вашем примере.)
Первый набор примерных данных:
$ awk -vOFS='\t' '{ r=""; delete t; for (i=1;i<=NF;++i) { if (!t[$i]++) { r = r ? r OFS $i : $i } } print r }' file
A B1 C1
B B2 D2
C C12 C13
D D3 D5 D9
G F2
Второй набор примеров данных (тот же awk
скрипт):
$ awk -vOFS='\t' '{ r=""; delete t; for (i=1;i<=NF;++i) { if (!t[$i]++) { r = r ? r OFS $i : $i } } print r }' file
A CD274 PDCD1LG2 CD276
B NEK2 NEK6 NEK10 NEKL-4
C TNFAIP3 OTUD7B
D DUSP16 DUSP4 DUSP8 VHP-1
E AGO2
Сценарий считывает входной файл file
построчно и для каждой строки проходит через каждое поле, формируя выходную строку, r
. Если значение в поле уже было добавлено в строку вывода (, определяемую справочной таблицей t
, используемых значений поля ), то поле игнорируется, в противном случае оно добавляется.
Когда все поля входной строки обработаны, выводится построенная строка.
Разделитель выходных полей установлен на табуляцию через -vOFS='\t'
в командной строке.
Расшифровка сценария awk
:
{
r = ""
delete t
for (i = 1; i <= NF; ++i) {
if (!t[$i]++) {
r = r ? r OFS $i : $i
}
}
print r
}