Этот тип проблемы может быть сложно отладить. Для начала полезно изолировать его от проблем с доступом к сети или жесткому диску.
Это достигается путем устранения потенциальных причин до тех пор, пока вы не останетесь с виновником.
Прежде чем мы начнем, мы воспользуемся несколькими приложениями, которые вам, возможно, придется установить. Я не буду подробно рассказывать, как это сделать, я предполагаю, что вы знаете, как устанавливать приложения, и сделаете это, когда потребуется выполнить конкретный шаг.
Также мы будем использовать системную консоль. Для доступа к нему выполните следующие действия: Ctrl + Alt + F2 . Вы можете использовать аналогичную комбинацию клавиш, чтобы вернуться к основному дисплею, где находится графический рабочий стол. Это будет следующая комбинация клавиш: Ctrl + Alt + F1 .
Использование приложения nethogs
- хорошее место для начала. Мне нравится его использовать, поскольку он показывает приложения, которые пытаются получить доступ к сети. Возможно, одно из этих приложений вызывает зависание.
Прежде чем мы сможем использовать nethogs
, нам нужно определить, какой сетевой интерфейс используется нашей системой. Вот те, которые у меня есть на моем ноутбуке:
$ ip -o link show | cut -d" " -f2
lo:
em1:
wlp3s0:
virbr0:
virbr0-nic:
vboxnet0:
Я знаю по опыту, что моя беспроводная связь - wplp3s0
. Ethernet - это em1
. Начнем с WiFi.
$ sudo nethogs wlp3s0
Результатом этого типа вывода:
NetHogs version 0.8.0
PID USER PROGRAM DEV SENT RECEIVED
979 saml ../bin/google-chrome-stable wlp3s0 1.943 2.547 KB/sec
2376 saml /usr/bin/pidgin wlp3s0 0.000 0.000 KB/sec
21789 saml ssh wlp3s0 0.000 0.000 KB/sec
9618 saml ssh wlp3s0 0.000 0.000 KB/sec
10267 saml ssh wlp3s0 0.000 0.000 KB/sec
? root unknown TCP 0.000 0.000 KB/sec
TOTAL 1.943 2.547 KB/sec
Как только мы изолировали проблему от нескольких PID, которые кажутся однобокими из-за большого количества данных SENT
без получения данных, мы нужно погрузиться глубже и использовать strace
, чтобы попытаться увидеть, какой аспект этого сетевого доступа зависает. Для этого вы можете использовать strace
следующим образом:
$ strace -s 2000 -o somepid.log -p <PID>
Где
- это один из идентификаторов процесса, идентифицированных из nethogs
.
Если мы определили, что проблема не в нашей сети, следующим местом для исследования будет поиск того, есть ли у процесса проблемы с доступом к жесткому диску и блокировка каким-либо образом .
Это может быть сложнее отладить, но вы, вероятно, воспользуетесь такими инструментами, как lsof
, strace
и fatrace
для дальнейшего уточнения поиска.
Одно из мест, где вы можете довольно быстро определить, есть ли что-то подозрительное, - это отключить запуск любых приложений при входе в систему. Для этого в GNOME вы можете запустить этот диалог: gnome- свойства сеанса
.
В этом диалоговом окне я бы попытался отключить все или приложения, которые вы считаете подозрительными, и начал бы перезагружаться, чтобы увидеть, исчезнет ли проблема.
Проблема не в paste
и не в /dev/stdin
. Это с /dev/stderr
.
Все команды создаются с одним открытым входным дескриптором (0 :стандартный ввод )и двумя выходами (1 :стандартный вывод и 2 :стандартная ошибка ). Обычно к ним можно получить доступ с именами /dev/stdin
, /dev/stdout
и /dev/stderr
соответственно, но см. Насколько переносимы /dev/stdin, /dev/stdout и /dev/stderr? . Многие команды, в том числе paste
, также интерпретируют имя файла -
как значение STDIN.
Когда вы запускаете bb
отдельно, и STDOUT, и STDERR являются консолью, где обычно появляется вывод команды. Строки проходят через разные дескрипторы (, как показано вашим annotate-output
), но в конечном итоге оказываются в одном и том же месте.
Когда вы добавляете |
и вторую команду, создавая конвейер...
bb | paste /dev/stdin /dev/stderr
|
указывает оболочке соединить вывод bb
со входом paste
. paste
сначала пытается прочитать из /dev/stdin
, который (через некоторые символические ссылки )разрешается в свой собственный стандартный входной дескриптор (, который оболочка только что подключила ), поэтому строка 1
проходит.
Но оболочка/конвейер ничего не делает для STDERR. bb
по-прежнему отправляет(e1
e2
и т. д. )на консоль. Тем временем paste
пытается читать с той же консоли, которая зависает (до тех пор, пока вы что-нибудь не наберете ).
Ваша ссылка Почему я не могу прочитать /dev/stdout в текстовом редакторе? по-прежнему актуален здесь, потому что те же самые ограничения применяются к /dev/stderr
.
У вас есть команда, которая выдает как стандартный вывод, так и стандартную ошибку, и вы хотите paste
вывести эти две строки рядом друг с другом. Это означает два параллельных канала, по одному на каждую колонку. Конвейер оболочки ... |...
предоставляет один из них, а второй вам нужно будет создать самостоятельно,и перенаправить STDERR на это с помощью 2>filename
.
mkfifo RHS
bb 2>RHS | paste /dev/stdin RHS
Если это предназначено для использования в сценарии, вы можете предпочесть создать этот FIFO во временном каталоге и удалить его после использования.
Есть пара проблем со всей строкой, которую нам нужно проанализировать, а именно:
seq 2 | tee >(sed 's/^/e/' > /dev/stderr) | paste /dev/stdin /dev/stderr
Во-первых, последняя команда. Только stdout может проходить через канал:
$ seq2 | paste -
1
2
$ seq2 | paste - -
1 2
Читать нечегоstderr
:
$ seq 2 | paste - /dev/stderr
1 ^C
Вам нужно ^C
его, потому что он блокирует, из stderr
нечего читать.
Даже если вы создаете некоторый вывод для stderr
, он не проходит через канал :
$ { seq 2; seq 3 4 >/dev/stderr; } | paste - /dev/stderr
1 3
4
Точно так же, как и раньше, 1
печатается, а paste
блокируется, ожидая stderr
.
Остальные 2 числа отправлялись прямо в консоль и печатались (независимо ).
Вы можете ввести некоторые данные в stderr
в последней команде конвейера:
$ { seq 2; seq 3 4 >/dev/stderr; } | paste - /dev/stderr 2</dev/null
1
2
3
4
Кстати, это то же самое, что и 2>/dev/null
, чтобы избежать блокировки второго файлового дескриптора, используемого в команде paste
. Но напечатанные значения поступают непосредственно из seq 3 4
, перенаправленных на консоль, а не из paste
.Это делает то же самое:
$ { seq 2; seq 3 4 >/dev/tty; } | paste - /dev/stderr 2</dev/null
1
2
3
4
И это не блокирует:
$ seq 2 | tee >(sed 's/^/e/' > /dev/stderr) |
paste /dev/stdin /dev/stderr 2</dev/null
1
2
e1
e2
Во-вторых, вывод tee
не обязательно должен быть «в порядке».`tee `и `bash `порядок замены процессов
И на самом деле :Результат подстановки процесса не обязательно должен быть «в порядке» :Вывод замены процесса не соответствует порядку
$ echo one; echo two > >(cat); echo three;
one
three
two
Фактически, в некоторых примерах, если вы попробуете несколько раз, вы можете получить разные порядки. недетерминированный вывод -независимых процессов, запущенных одновременно, путем подстановки процессов
$ printf '%s\n' {0..1000} | tee >(head -n2) >(sort -grk1,1 | head -n3) >/dev/null
1000
999
998
0
1
Таким образом, нет, это невозможно сделать с заменой процессов и вставкой.
Вам нужно отдать приказ о казни:
$ seq 2 | { while read a; do printf "%s %s\n" "$a" "e$a" ; done; }
1 e1
2 e2
Итак, ваша функция bb, которая (в основном )содержит:
| tee >(sed 's/^/e/')
Что можно проверить с помощью:
$ printf '%s\n' {0..1000} | tee >(sort -grk1,1 | head -n3 >&2) | head -n 2
0
1
291
290
289
Должен выводить 0, 1, 1000, 999, 998 в таком порядке, но часто это не так.
То есть :Это внутренне в -стабильном.
Единственным безопасным решением для bb является избежание любой замены процесса.
И, воспользовавшись тем, что {…}
захватывает как stdout, так и stderr, пример:
$ bash -c '{ echo test-str >/dev/stderr; }' 2>/dev/null
Нет вывода, удалите 2 для подтверждения.
Это будет работать для bb:
$ bb() { seq 5 | tee /dev/stderr | sed 's/^/e/'; }
И используйте FIFO для вставки:
$ mkfifo out2
$ bb 2>out2 | paste out2 -
1 e1
2 e2
3 e3
4 e4
5 e5
Вам потребуется установить ловушку для удаления файла fifo и проверить, существует ли файл fifo перед его созданием.
Похоже, работает переносимо во всех оболочках (, совместимых с синтаксисом Almquist ), который я тестировал. Не полностью проверено, запросите подтверждение у других пользователей, могут быть какие-то еще неизвестные сюрпризы.