Выполнение команд на рыбе WSL с помощью подпроцесса

#python #subprocess #windows-subsystem-for-linux

Вопрос:

Я установил WSL(Ubuntu), и теперь я хочу получить доступ к fish из WSL и выполнить команду, такую как дата из него. Как я могу это сделать?

Вот моя попытка!

 import subprocess
subprocess.run(["wsl", "fish"], shell=True)
subprocess.run(["date"], shell=True)
 

Вывод показывает выполнение до 2-й строки кода, но не выполнение команды date в терминале fish. Есть какое-нибудь решение для этого?

Комментарии:

1. Вы используете это из Windows Python или WSL?

2. Я использую Windows python.

Ответ №1:

Предполагая, что вы просто хотите захватить выходные данные, наиболее эффективным вызовом должен быть:

 cp = subprocess.run(["wsl", "-e", "date"], capture_output=True)
date = cp.stdout
 

Указав -e , вы полностью пропускаете оболочку, что позволяет избежать накладных расходов при запуске оболочки.

Если вы действительно хотите заставить его работать внутри fish :

 cp = subprocess.run(["wsl", "-e", "fish", "-c", "date"], capture_output=True)
date = cp.stdout
 

Более подробно:

Если fish это ваша оболочка по умолчанию, то вам действительно не нужно указывать ее в качестве аргумента для wsl команды. Вы можете убедиться в этом, выполнив следующие действия в PowerShell или CMD:

 wsl ps -eH
 
   PID TTY          TIME CMD
    1 ?        00:00:00 init
   21 ?        00:00:00   init
   22 ?        00:00:00     init
   23 pts/0    00:00:00       fish
   30 pts/0    00:00:00         ps

 

Обратите внимание, что ps команда, хотя и выполняется без fish командной строки WSL, все равно выполняется в оболочке по умолчанию.

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

 wsl -e ps -ef
 
   PID TTY          TIME CMD
    1 ?        00:00:00 init
   11 ?        00:00:00   init
   12 ?        00:00:00     init
   13 pts/0    00:00:00       ps
 

Вы заметите, что ни одна оболочка не запущена. Это вариант, который я рекомендовал выше ["wsl","-e","date"] в Python.

Допустим, fish это не ваша оболочка по умолчанию, и все же вы хотите, чтобы она работала.

 wsl -e fish -c "ps -eH"
 
   PID TTY          TIME CMD
    1 ?        00:00:00 init
   20 ?        00:00:00   init
   21 ?        00:00:00     init
   22 pts/0    00:00:00       fish
   29 pts/0    00:00:00         ps
 

Но не делайте wsl fish "ps -eH" (или wsl fish -c date ). Это будет запускать рыбу внутри рыбы, что очень расточительно:

    PID TTY          TIME CMD
    1 ?        00:00:00 init
   11 ?        00:00:00   init
   12 ?        00:00:00     init
   13 pts/0    00:00:00       fish
   20 pts/0    00:00:00         fish
   22 pts/0    00:00:00           ps
 

Ответ №2:

С помощью вашей команды сначала subprocess.run() запускается процесс, а затем ожидает его завершения. Как вы знаете, wsl fish на самом деле это не заканчивается само по себе, что означает, что ваше приложение python теперь будет заблокировано на неопределенный срок.

Что вы на самом деле хотите сделать, так это запустить процесс, отправить ему данные через его STDIN и прочитать его вывод STDOUT.

Однако вы не можете сделать это так — например, вы не хотите блокировать интерпретатор!

 proc = Popen(["wsl", "fish"], stdin=PIPE, stdout=PIPE, stderr=PIPE)
output, err = proc.communicate(b"date")
print(output)
 

communicate также блоки. Если бы вы хотели, чтобы это продолжалось, вы бы сделали proc.stdin.write() это, а затем proc.stdout.readline()

Ответ №3:

Первый подпроцесс.запуск запустит интерактивную раковину рыбы.

Только когда вы наберете exit, то date запуститесь.