Как удалить строки «Отказ в соединении» из «>/dev/tcp/ip/port»

Это болезненно в оболочках, потому что встроенная функция waitне выполняет «ожидание любого», она выполняет «ожидание всех». waitбез аргумента ожидает выхода всех дочерних процессов и возвращает 0. waitс явным списком процессов ждет выхода всех из них и возвращает статус последнего аргумента. Чтобы дождаться нескольких потомков и получить их статус выхода, вам нужен другой подход. waitможет дать вам статус выхода, только если вы знаете, какой ребенок уже мертв.

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

mkfifo status_pipe
children=0
{ child1; echo 1 $? >status_pipe; } & children=$((children+1))
{ child2; echo 2 $? >status_pipe; } & children=$((children+1))
max_status=0
while [ $children -ne 0 ]; do
  read -r child status <status_pipe
  children=$((children-1))
  if [ $status -gt $max_status ]; then
    max_status=$status
  fi
done
rm status_pipe

Обратите внимание, что это будет заблокировано навсегда, если одна из подоболочек умрет, не сообщив о своем статусе. В типичных условиях этого не произойдет, но это может произойти, если подоболочка была убита вручную или если подоболочке не хватило памяти.

Если вы хотите что-то сделать, как только один из потомков выйдет из строя, замените if [ $status -gt $max_status ]; then …на if [ $status -ne 0 ]; then ….

1
23.05.2020, 07:13
1 ответ

Измените порядок перенаправления и сообщите bashкакой stderr должен быть перед stdin

$ >/dev/tcp/127.0.0.1/8088 2>/dev/nul
bash: connect: Connection refused
bash: /dev/tcp/127.0.0.1/8088: Connection refused
$ 2>/dev/null >/dev/tcp/127.0.0.1/8088 && echo open || echo closed
closed
$ 

Причина сбоя первой версии заключается в том, что перенаправления обрабатываются в порядке их появления, поэтому в >/dev/tcp/127.0.0.1/8088 2>/dev/nullкогда происходит перенаправление на порт, поток stderr еще НЕ был перенаправлен. Вы можете ясно увидеть соответствующий системный вызов dup2()для перенаправления stderr (или его отсутствие в случае сбоя команды )в диагностическом выводе с помощью утилиты strace

.
$ strace -e dup2,connect  -f bash -c '>/dev/tcp/127.0.0.1/8088 2>/dev/null'
connect(3, {sa_family=AF_INET, sin_port=htons(8088), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 ECONNREFUSED (Connection refused)
bash: connect: Connection refused
bash: /dev/tcp/127.0.0.1/8088: Connection refused
+++ exited with 1 +++
$ strace -e dup2,connect  -f bash -c '2>/dev/null >/dev/tcp/127.0.0.1/8088 '
dup2(3, 2)                              = 2
connect(3, {sa_family=AF_INET, sin_port=htons(8088), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 ECONNREFUSED (Connection refused)
dup2(10, 2)                             = 2
+++ exited with 1 +++
$ 
1
18.03.2021, 23:33

Теги

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