import collections
import signal
import subprocess
import threading
import time
class ChildProcessReader(threading.Thread):
def __init__(self, args: list[str], *, encoding: str | None = None, errors: str = 'ignore', exit_timeout: float = 1.0):
super().__init__(name=f'Monitor {args!r}', daemon=True)
self._encoding = encoding
self._errors = errors
self._exit_timeout = exit_timeout
self._queue = collections.deque()
self._child = subprocess.Popen(args,
stdin=subprocess.DEVNULL, # стандартный вход отключен
stdout=subprocess.PIPE, # перехватываем стандартный вывод
stderr=subprocess.STDOUT, # стандартный вывод ошибок направляем на стандартый вывод
)
self.start()
@property
def running(self) -> bool:
'''Возвращает True, если процесс ещё жив.'''
return self._child is not None
@property
def output(self) -> collections.deque:
'''Очередь, в которую будут складываться получаемые от процесса строки.'''
return self._queue
def stop(self) -> None:
'''Останавливает процесс - сначала "по хорошему", потом принудительно.'''
if self._child is None:
return
try:
self._child.send_signal(signal.CTRL_C_EVENT)
self._child.wait(self._exit_timeout)
except subprocess.TimeoutExpired:
self._child.terminate()
except KeyboardInterrupt:
pass
finally:
self._child = None
def run(self) -> None:
'''Тело потока.'''
try:
while self._child.poll() is None: # рабочий цикл крутится, пока дочерний процесс жив.
stdout_data = self._child.stdout.read1()
if self._encoding is not None:
stdout_data = stdout_data.decode(self._encoding, errors=self._errors)
self._queue.append(stdout_data)
except KeyboardInterrupt:
pass
finally: # по выходу из цикла завершаем процесс
self.stop()
if __name__ == '__main__':
child = ChildProcessReader(
# выполняемая команда
['ping', '-t', '127.0.0.1'],
# кодировка, в которой отдаёт данные твой процесс. None - отдавать байты как есть.
encoding='cp866', errors='ignore',
# сколько ждать завершения процесса
exit_timeout=1.0
)
# процесс (и поток) стартуют немедленно по созданию экземпляра класса
try:
while child.running:
# вместо просто цикла тебе лучше периодически выполнять код ниже иным способом
# например, если у тебя GUI на tkinter, используй метод .after()
try: # пытаемся получить очередную строку от процесса
data = child.output.popleft()
except IndexError: # ничего нет, буфер пуст
# это просто реакция на отсутствие текста. Можно вообще ничего не делать.
print('.', end='', flush=True)
time.sleep(0.1) #
else: # получили строку, обрабатываем
print(f'\n> {data!r}')
except KeyboardInterrupt:
print('\nStopping')
finally: # в итоге надо будет прибить дочерний процесс
child.stop()
validNumber = int.TryParse(readResult, out numValue);
после чего и думать ;)namespace ConsoleApp4
{
internal class Program
{
static void Main(string[] args)
{
string? readResult;
int numValue;
Console.Write("Enter an integer value between 5 and 10: ");
do
{
readResult = Console.ReadLine();
bool validNumber = false;
validNumber = int.TryParse(readResult, out numValue);
#if DEBUG
Console.WriteLine($"debug 'numValue='{numValue}");
Console.WriteLine($"debug 'validNumber='{validNumber}");
#endif
if (validNumber == true)
{
if (numValue < 5 || numValue > 10)
Console.Write($"You entered {numValue}. Please enter a number between 5 and 10: ");
}
else Console.Write("Sorry, you entered an invalid number, please try again: ");
} while (numValue < 5 || numValue > 10);
Console.WriteLine($"Your input value ({numValue}) has been accepted.");
}
}
}
namespace ConsoleApp4
{
internal static class Program
{
static void Main(string[] args)
{
var numValue = 0;
var inValidValue = false;
var validNumber = false;
"Enter an integer value between 5 and 10:".print();
do
{
validNumber = int.TryParse(Console.ReadLine(), out numValue);
inValidValue = numValue < 5 || numValue > 10;
#if DEBUG
$".. debug 'numValue={numValue}'".print();
$".. debug 'validNumber={validNumber}'".print();
$".. debug 'validValue={inValidValue}'".print();
#endif
if (validNumber)
{
if (inValidValue)
$"You entered {numValue}. Please enter a number between 5 and 10: ".print();
}
else "Sorry, you entered an invalid number, please try again: ".print();
} while (inValidValue);
$"Your input value ({numValue}) has been accepted.".print();
}
static void print(this string s) => Console.WriteLine(s);
}
}
namespace fanc_minimal
{
internal static class Program
{
static void Main(string[] args)
{
string checkValue(bool goodValue, bool correctNumber, int Value) => (goodValue, correctNumber) switch
{
(true, true) => $"Your input value ({Value}) has been accepted.",
(false, true) => $"You entered {Value}. Please enter a number between 5 and 10:",
_ => "Sorry, you entered an invalid number, please try again:"
};
Console.WriteLine("Enter an integer value between 5 and 10:");
for (var validValue = false; !validValue; )
{
var validNumber = int.TryParse(Console.ReadLine(), out var numValue);
Console.WriteLine(checkValue(validValue = numValue >= 5 && numValue <= 10, validNumber, numValue));
}
}
}
}
но это пример оголтелого минимализма строк ))namespace func_next
{
internal static class Program
{
static void Main(string[] args)
{
const int min = 5;
const int max = 10;
var value = min - 1;
var stop = false;
bool success() => value >= min && value <= max;
string check() => (int.TryParse(Console.ReadLine(), out value), stop = success()) switch
{
(true, true) => $"Your input value ({value}) has been accepted. Press Enter to Exit )))",
(true, false) => $"You entered {value}. Please enter a number between 5 and 10:",
_ => "Sorry, you entered an invalid number, please try again:"
};
for ("Enter an integer value between 5 and 10:".print(); !stop; check().print()) ;
}
static void print(this string s) => Console.WriteLine(s);
}
}
.. и снова.. лишь пример перфекционизма.. но код содержит взаимозависмости, не допустимые в большом проекте ))if
.. ну и показать мощь сишныхfor
)))namespace func_next
{
internal static class Program
{
static void Main(string[] args)
{
const string welcome = "Enter an integer value between 5 and 10:";
const int min = 5;
const int max = 10;
var value = min - 1;
var stop = false;
bool success() => value >= min && value <= max;
bool valid() => int.TryParse(Console.ReadLine(), out value);
string check() => (valid(), stop = success()) switch
{
(true, true) => $"Your input value ({value}) has been accepted.",
(true, false) => $"You entered {value}. Please enter a number between 5 and 10:",
_ => "Sorry, you entered an invalid number, please try again:"
};
for (welcome.print(); !stop; check().print()) ;
}
static void print(this string s) => Console.WriteLine(s);
}
}
namespace func_next
{
internal static class Program
{
static void print(this string s) => Console.WriteLine(s);
static void Main(string[] args)
{
const int min = 5;
const int max = 10;
var value = min - 1;
string welcome() => $"Enter an integer value between {min} and {max}:";
string accepted() => $"Your input value ({value}) has been accepted.";
string repeat() => $"You entered {value}. Please enter a number between {min} and {max}:";
const string ups = "Sorry, you entered an invalid number, please try again:";
bool valid() => int.TryParse(Console.ReadLine(), out value);
bool success() => value >= min && value <= max;
var stop = false;
string check() => (valid(), stop = success()) switch
{
(true, true) => accepted(),
(true, false) => repeat(),
_ => ups
};
for (welcome().print(); !stop; check().print()) ;
}
}
}
шарм ситуации в том, что тушка программы сводится к строкеfor (welcome.print(); !stop; check().print()) ;
а все остальное - лишь определение "понятий"... обожаю функциональный стиль ))namespace func_next
{
internal static class Program
{
static void print(this string s) => Console.WriteLine(s);
static void Main(string[] args)
{
var min = 5;
var max = 10;
var value = min - 1;
string welcome() => $"Enter an integer value between {min} and {max}:";
string accepted() => $"Your input value ({value}) has been accepted.";
string repeat() => $"You entered {value}. Please enter a number between {min} and {max}:";
const string ups = "Sorry, you entered an invalid number, please try again:";
var valid = false;
bool get() => valid = int.TryParse(Console.ReadLine(), out value);
bool success() => value >= min && value <= max && valid;
var stop = false;
string check() => (get(), stop = success()) switch
{
(true, true) => accepted(),
(true, false) => repeat(),
_ => ups
};
for (welcome().print(); !stop; check().print()) ;
}
}
}
.. тут уже полшага до модификации min/max на ходу ;)) Start-Process -FilePath "docker" -ArgumentList "version" -NoNewWindow -PassThru
Start-Process -FilePath "docker" -ArgumentList "version" -NoNewWindow -RedirectStandardOutput <output file> -RedirectStandardError <error file>
Как узнать какая версия подходит для .net 6.0? Является ли она обратно совместимой?