Как обнаружить ошибку с помощью подстановки процесса

Это больше относится к программированию , но я бы подошел к этому, прочитав файл построчно, сформировав комбинации, которые присутствуют в каждой строке, подсчитав их появление в хеш-таблице.

Часть о формировании комбинаций - это то, для чего вы захотите использовать библиотеку.

Perl приходит на помощь, Algorithm :: Combinatorics имеет готовую функцию для перечисления комбинаций. Судя по примерам, сделать что-то подобное довольно легко. Учитываются только комбинации из двух, не стесняйтесь улучшать его.

perl -MAlgorithm::Combinatorics=combinations -lane '
   $i = combinations([sort @F], 2); 
   while ($x = $i->next) { $count{join "-", @$x}++ }
   END {printf "%s: %d\n", $_, $count{$_} foreach keys %count  } 
   '  < ids > counts | sort -nk2 | tail -3
1010-1020: 3
1001-1010: 4
1004-1010: 4

Я предположил, что порядок чисел в каждой строке не имеет значения, поэтому отсортировал ввод. (Я думаю, что комбинаций сохраняет порядок элементов, поэтому результат не имеет несортированных дубликатов.) С числами примеров я получил примерно 30000 строк, обрабатываемых в секунду.

3
10.07.2017, 02:21
4 ответа

В вашем примере:

cat <(datE); echo $?

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

Если убрать промежуточный шаг, все будет работать так, как вы ожидаете:

$ datE; echo $?
datE: command not found
127

Если вы хотите, чтобы bashпрервал работу при любых сбоях в конвейере и любой неперехваченной ошибке, выполните следующие две команды:

set -e
set -o pipefail

Другие оболочки могут предоставлять аналогичные настройки.

-1
27.01.2020, 21:46

Альтернативой использованию подстановки процесса является использование /dev/stdinв качестве аргумента файла, чтобы каналы работали должным образом:

set -o pipefail
datE | cat /dev/stdin

Приведенный выше пример немного надуман, так как catбудет считываться со стандартного ввода, если не задан файл arg. Это полезно, когда команде нужно передать файл.

2
27.01.2020, 21:46

В bashзамены процессов запускаются как фоновые задания. Вы можете получить pid ведущего процесса последнего с помощью $!, и вы можете получить его статус выхода с помощью wait thatpid, как и для других фоновых заданий :

.
$ bash -c 'cat <(exit 3); wait "$!"; echo "$?"'
3

Это не поможет, если вам нужно использовать две подстановки процессов в одной команде, как в diff <(cmd1) <(cmd2).

$ bash -c 'cat <(exit 3) <(exit 4); wait "$!"; echo "$?"'
4

Pid из exit 3выше потерян

Это можно восстановить с помощью такого трюка:

unset -v p1 p2
x='!'
cat <(exit 3) ${!x#${p1=$!}} <(exit 4) ${!x#${p2=$!}}

где оба pid хранятся в $p1и $p2, но это бесполезно, так как только последний вставляется в таблицу заданий оболочки, а waitотказывается ждать $p1, ошибочно утверждая, что он не является потомком этой оболочки , даже если $p1еще не завершился:

$ cat test-script
unset -v p1 p2
x='!'
set -o xtrace
cat <(echo x; exec >&-; sleep 1; exit 3) ${!x#${p1=$!}} <(exit 4) ${!x#${p2=$!}}
ps -fH
wait "$p1"; echo "$?"
wait "$p2"; echo "$?"
$ bash test-script
++ echo x
++ exec
++ sleep 1
+ cat /dev/fd/63 /dev/fd/62
++ exit 4
x
+ ps -fH
UID        PID  PPID  C STIME TTY          TIME CMD
chazelas 15393  9820  0 21:44 pts/4    00:00:00 /bin/zsh
chazelas 17769 15393  0 22:19 pts/4    00:00:00   bash test-script
chazelas 17770 17769  0 22:19 pts/4    00:00:00     bash test-script
chazelas 17772 17770  0 22:19 pts/4    00:00:00       sleep 1
chazelas 17776 17769  0 22:19 pts/4    00:00:00     ps -fH
+ wait 17770
test-script: line 6: wait: pid 17770 is not a child of this shell
+ echo 127
127
+ wait 17771
+ echo 4
4
$ ++ exit 3

Подробнее об этом в Ответ @mosvy на Запуск асинхронных задач и получение их кода выхода и вывода в bash

2
27.01.2020, 21:46

Не существует идиоматического способа заставить вызывающий процесс(bash)распространить ошибку на cat, поскольку они запускаются отдельно. Единственное, что связывает catи datE, это, вероятно, временный файл с именем /dev/fd/63, время жизни которого связано со временем жизни содержащего оператора оболочки.

Самое простое исправление, о котором я знаю, это поместить вывод во временный файл и проверить код возврата dateE.

Что-то вроде:

# Make a tempfile
tmpfile=$(mktemp)
# Delete the tempfile when this shell process exits
trap "rm ${tmpfile}" 0
# Run the command and check for success
if datE > "${tmpfile}"; then
    cat < "${tmpfile}"
else
    # Report the error.
fi

При этом существуют хакерские способы, которые могут включать другие файлы, используемые для распространения значения ошибки. Но общая идея заключается в том, что процессы не могут (и не должны )изменять свои родительские или одноуровневые процессы, если только не существует какого-либо взаимно согласованного общего состояния (, такого как файл, очередь FIFO, канал и т. д. ).

1
27.01.2020, 21:46

Теги

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