Применение системных вызовов в языке Python
Основы системных вызовов в Python
Системные вызовы - интерфейс между пользовательскими программами и ядром операционной системы. В Python доступ к ним реализован через стандартные модули, такие как os, subprocess и ctypes. Выбор конкретного инструмента зависит от задачи: запуск внешней программы, управление процессами, работа с файловыми дескрипторами или прямой вызов системных функций.
Какое решение самое надёжное для выполнения внешних команд?
Наиболее универсальным и безопасным способом является использование subprocess.run() с параметром shell=False. Этот метод не зависит от интерпретации команд оболочкой, что исключает риски внедрения команд (shell injection).
import subprocess
result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
print(result.stdout)System calls python (системные вызовы в python)
Пояснение: команда передаётся списком, первый элемент - имя программы. Аргумент capture_output=True сохраняет стандартный вывод и ошибки. Результат возвращается в объекте CompletedProcess.
Типичная ошибка: попытка передать команду строкой без разбиения - subprocess.run('ls -l') вызовет исключение. Решение: всегда использовать список или строку с shell=True (но последнее менее безопасно).
Как выполнить простую команду без захвата вывода?
Старый способ - функция os.system(). Она запускает команду в оболочке и возвращает код завершения. Удобна для быстрых скриптов, но не позволяет получить вывод.
import os
retcode = os.system('mkdir temp_dir')
print(f'Код возврата: {retcode}')создание системных утилит python (создание системных утилит на python)
Цель: выполнение команды, когда результат не нужен, например, создание каталога.
Ошибка: утечка ресурсов, если команда запускается без ожидания. Также зависит от оболочки. Рекомендуется использовать subprocess.
Как получить вывод команды простым способом?
Функция os.popen() открывает канал для чтения или записи. Позволяет считывать вывод построчно, но устарела и заменена на subprocess.
import os
with os.popen('uptime', 'r') as pipe:
output = pipe.read()
print('Время работы:', output.strip())
Python open exe (запуск exe файла из python)
Случаи использования: быстрый скрипт, где не требуется сложный контроль.
Проблема: необходимо закрывать канал вручную. В Python 3 рекомендуется использовать subprocess.
Как управлять процессом в реальном времени?
Класс subprocess.Popen даёт полный контроль: можно отправлять данные на stdin, читать stdout в реальном времени, завершать процесс.
import subprocess
proc = subprocess.Popen(['ping', '-c', '4', 'google.com'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
try:
outs, errs = proc.communicate(timeout=10)
print(outs.decode())
except subprocess.TimeoutExpired:
proc.kill()
print('Процесс превысил время')библиотека команд python (библиотека для выполнения команд в python)
Цель: интерактивное взаимодействие с программой.
Ошибка: зависание при чтении, если не использовать communicate() или таймаут. Решение: установить timeout или читать построчно.
Как вызвать системную функцию напрямую, минуя обёртки Python?
Модуль ctypes позволяет вызывать функции из динамических библиотек (libc). Например, низкоуровневый вызов open().
import ctypes
libc = ctypes.CDLL('libc.so.6')
fd = libc.open(b'/tmp/test.txt', 0o002 | 0o100) # O_RDWR | O_CREAT
if fd != -1:
libc.write(fd, b'Hello from syscall\n', 20)
libc.close(fd)Когда используется: для редких системных вызовов, отсутствующих в os (например, inotify, signalfd).
Опасность: ошибки в типах аргументов ведут к падению интерпретатора. Необходимо проверять коды возврата. Рекомендуется осваивать после глубокого понимания C.
Как использовать системные вызовы для файлового ввода-вывода?
Модуль os предоставляет обёртки для POSIX-системных вызовов: open(), read(), write(), stat() и других. Это эффективно при работе с большими объёмами данных или низкоуровневыми операциями.
import os
fd = os.open('data.bin', os.O_RDONLY)
try:
data = os.read(fd, 1024)
print('Прочитано', len(data), 'байт')
finally:
os.close(fd)Случаи: буферизованный ввод/вывод, работа с сетевыми сокетами, каналами.
Ошибка: забыть закрыть файловый дескриптор - утечка. Использовать контекстный менеджер (with os.fdopen()) или try/finally.
Расширенные примеры системных вызовов
Пример 1: Использование модуля os для создания символической ссылки и проверки разрешений
import os
# создание символической ссылки
os.symlink('/etc/passwd', '/tmp/passwd_link')
# получение информации о файле
stat_info = os.stat('/tmp/passwd_link')
print('Размер:', stat_info.st_size)
print('Права:', oct(stat_info.st_mode))
# удаление ссылки
os.unlink('/tmp/passwd_link')Размер: 0 Права: 0o120777
Пояснение: symlink() создаёт ссылку, stat() возвращает метаданные. Права 0o120777 характерны для ссылок. Функция unlink() удаляет ссылку, а не оригинальный файл.
Пример 2: Прямой вызов системного вызова mmap через ctypes
import ctypes, mmap
# открытие файла и получение размера
fd = os.open('/dev/zero', os.O_RDONLY)
size = 4096
# вызов mmap через ctypes
libc = ctypes.CDLL('libc.so.6')
libc.mmap.restype = ctypes.c_void_p
addr = libc.mmap(None, size, 1, 0x01, fd, 0) # PROT_READ, MAP_SHARED
if addr:
# чтение данных по адресу
buf = ctypes.string_at(addr, size)
print('Прочитано', len(buf), 'байт нулей')
libc.munmap(addr, size)
os.close(fd)Прочитано 4096 байт нулей
Пояснение: mmap отображает файл в память. Используется для быстрого доступа к данным. В Python есть встроенная функция mmap.mmap(), но ctypes даёт гибкость.
Пример 3: Отслеживание изменений файлов с помощью inotify (через ctypes)
import ctypes, os
# загрузка библиотеки
libc = ctypes.CDLL('libc.so.6')
# создание inotify-инстанции
inotify_fd = libc.inotify_init()
# добавление наблюдения за каталогом
wd = libc.inotify_add_watch(inotify_fd, b'/tmp', 0x00000100 | 0x00000002) # IN_CREATE | IN_DELETE
# чтение события (блокирующая операция)
buf = ctypes.create_string_buffer(1024)
nbytes = libc.read(inotify_fd, buf, 1024)
print('Получено событие:', nbytes, 'байт')
libc.close(inotify_fd)Получено событие: 16
Пояснение: inotify_init() создаёт дескриптор, inotify_add_watch подписывается на события. Чтение возвращает структуры. Необходимо обрабатывать битовые маски.
Пример 4: Управление приоритетами процессов через os.sched_setscheduler
import os, time
policy = os.SCHED_RR
param = os.sched_param(1)
try:
os.sched_setscheduler(0, policy, param)
print('Приоритет установлен')
time.sleep(0.1)
except PermissionError:
print('Недостаточно прав для изменения приоритета')Недостаточно прав для изменения приоритета
Пояснение: для установки реального времени требуются привилегии root. Функция sched_setscheduler(0, policy, param) где 0 - текущий процесс. Политики: SCHED_OTHER, SCHED_RR, SCHED_FIFO.
Пример 5: Передача файлового дескриптора через сокет (аномальный пример)
import os, socket
# создание сокета и файла
sock1, sock2 = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
fd = os.open('/dev/null', os.O_RDONLY)
# отправка дескриптора через ancillary data
import struct
msg = b'fd'
ancdata = [(socket.SOL_SOCKET, socket.SCM_RIGHTS, struct.pack('i', fd))]
sock1.sendmsg([msg], ancdata)
# приём на другом конце
data, ancdata, flags, addr = sock2.recvmsg(1, socket.CMSG_SPACE(4))
received_fd = struct.unpack('i', ancdata[0][2])[0]
print('Получен дескриптор:', received_fd)
os.close(fd)
os.close(received_fd)Получен дескриптор: 3
Пояснение: передача файловых дескрипторов между процессами через Unix sockets используется для эффективного обмена открытыми файлами.