Предсказание PID ранее начатой ​​команды SSH

Это самое странное.

В сценарии я запускаю туннель SSH следующим образом:

ssh -o StrictHostkeyChecking=no -fND 8080 foo@bar 

Это запускает экземпляр ssh который переходит в фоновый режим, и выполнение сценария продолжается. Затем я сохраняю его PID (для его убийства позже), используя bash $! переменная . Чтобы это сработало, я добавляю & к команде ssh даже если он уже идет в фоновом режиме сам по себе (иначе $! Не содержит ничего). Таким образом, например, следующий скрипт:

 #!/bin/bash ssh -o StrictHostkeyChecking=no -fND 8080 foo@bar & echo $! pgrep -f "ssh -o StrictHostkeyChecking=no -fND 8080 foo@bar" 

выходы

 (some ssh output) 28062 28062 

… два раза тот же PID, как и ожидалось. Но теперь, когда я выполняю эту точную последовательность команд с терминала, вывод PID через $! (в том смысле, что это не PID экземпляра ssh ). От терминала:

 $ ssh -o StrictHostkeyChecking=no -fND 8080 foo@bar & [1] 28178 (some ssh output) $ echo $! 28178 $ pgrep -f "ssh -o StrictHostkeyChecking=no -fND 8080 foo@bar" 28181 

Это не всегда 3 номера. Я также заметил разницу в 1 или 2. Но это никогда не тот же PID, как я и ожидал, и, как и в случае, когда эта последовательность команд запускается внутри скрипта.

  1. Может кто-нибудь объяснить, почему это происходит? Я думал, что это может быть связано с тем, что начальный вызов ssh фактически вызывает другой процесс, но почему он работает из сценария?

  2. Это также заставило меня сомневаться в том, что использование $! в моем скрипте, чтобы получить ssh PID, как описано выше, действительно будет работать (хотя он до сих пор). Действительно ли это действительно? Я чувствовал, что это «чище», чем использование pgrep

  • Проблема с несколькими файлами, связанными с SSH-соединениями
  • Двойная переадресация портов - SSH
  • SSH на несколько удаленных машин через ssh tunnel
  • пересылать весь трафик mysql в туннель ssh
  • Правильное закрытие туннеля SSH с несколькими точками
  • ограничение квоты на передачу TCP пользователя
  • Почему SSH-вход работает в оболочке, но не работает во всех третьих лицах через ssh-туннель?
  • Шифрование Linux LPD для Windows (ipsec / ssh tunnel / other)
  • One Solution collect form web for “Предсказание PID ранее начатой ​​команды SSH”

    Оболочка $! переменная знает только pid процесса, запускаемого оболочкой. Как вы подозревали, вызов ssh с использованием -f запускает собственный процесс, поэтому он может перейти в фоновый режим, поэтому общее дерево процессов выглядит как [1]:

     shell | +--ssh<1> (pid is $!) | +--ssh<2> (pid is different) 

    ssh<1> выходит очень скоро после вызова; поэтому значение в $! вряд ли будет полезна. Это ssh<2> который осуществляет удаленную связь и выполняет ваше туннелирование для вас, и единственный способ надежно получить его PID – это изучить таблицу процессов, как вы это делаете с pgrep [2]. Метод pgrep вероятно, будет правильным здесь.

    Что касается того, почему он работает в скрипте, но не в интерактивном режиме, это, вероятно, состояние гонки. Поскольку вы помещаете первый ssh в фоновом режиме, shell и ssh выполняются одновременно, а ssh выполняет некоторую умеренную криптографическую аутентификацию с процессором и некоторые сетевые обратные вызовы. Вероятно, что pgrep вы запускаете в скрипте, просто запускается до того, как ssh<1> перейдет в фоновый режим. Чтобы обойти это, позже запустите pgrep либо вызовом sleep , либо просто позвонив только тогда, когда вам действительно понадобится PID.

    [1]: Технически, это может быть сложнее, чем это, если ssh использует классическую двойную fork для фона. В этом случае между ними будет еще один эфемерный ssh процесс.

    [2]: Если вы не systemd и вы используете группы или что-то, чтобы отслеживать всех ваших детей. Который вы нет.

    Linux и Unix - лучшая ОС в мире.