pty
— Verktyg för pseudoterminal¶
Källkod: Lib/pty.py
Modulen pty
definierar operationer för hantering av pseudoterminalbegreppet: att starta en annan process och kunna skriva till och läsa från dess kontrollterminal programmatiskt.
Tillgänglighet: Unix.
Hanteringen av pseudoterminaler är i hög grad plattformsberoende. Den här koden är huvudsakligen testad på Linux, FreeBSD och macOS (den ska fungera på andra POSIX-plattformar men har inte testats grundligt).
Modulen pty
definierar följande funktioner:
- pty.fork()¶
Fork. Anslut underliggande kontrollterminal till en pseudoterminal. Returvärdet är
(pid, fd)
. Observera att barnet får pid 0 och att fd är invalid. Förälderns returvärde är barnets pid och fd är en filbeskrivare som är ansluten till barnets kontrollterminal (och även till barnets standardinmatning och -utmatning).Varning
På macOS är användningen av denna funktion osäker när den blandas med användning av system-API:er på högre nivå, och det inkluderar användning av
urllib.request
.
- pty.openpty()¶
Öppna ett nytt pseudoterminalpar, med
os.openpty()
om möjligt, eller emuleringskod för generiska Unix-system. Returnera ett par filbeskrivare(master, slave)
, för master- respektive slave-änden.
- pty.spawn(argv[, master_read[, stdin_read]])¶
Starta en process och anslut dess kontrollterminal till den aktuella processens standard io. Detta används ofta för att förvirra program som insisterar på att läsa från den kontrollerande terminalen. Det förväntas att processen som startas bakom pty så småningom kommer att avslutas, och när den gör det kommer spawn att returneras.
En loop kopierar STDIN i den aktuella processen till barnet och data som tas emot från barnet till STDOUT i den aktuella processen. Det signaleras inte till barnet om STDIN i den aktuella processen stängs ned.
Funktionerna master_read och stdin_read får en filbeskrivare som de ska läsa från och de ska alltid returnera en byte-sträng. För att tvinga spawn att returnera innan barnprocessen avslutas bör en tom bytearray returneras för att signalera slutet på filen.
Standardimplementeringen för båda funktionerna läser och returnerar upp till 1024 byte varje gång funktionen anropas. Återuppringningen master_read får pseudoterminalens master file descriptor för att läsa utdata från barnprocessen, och stdin_read får file descriptor 0 för att läsa från den överordnade processens standardinmatning.
Om en tom bytesträng returneras från något av återuppringningsprogrammen tolkas det som ett EOF-villkor (end-of-file) och det återuppringningsprogrammet kommer inte att anropas efter det. Om stdin_read signalerar EOF kan den kontrollerande terminalen inte längre kommunicera med moderprocessen eller barnprocessen. Om inte barnprocessen kommer att avslutas utan någon indata kommer spawn att loopa för evigt. Om master_read signalerar EOF blir resultatet detsamma (åtminstone på Linux).
Returnerar utgångsstatusvärdet från
os.waitpid()
på underordnad process.os.waitstatus_to_exitcode()
kan användas för att konvertera utgångsstatus till en utgångskod.Utlöser en auditing event
pty.spawn
med argumentetargv
.Ändrad i version 3.4:
spawn()
returnerar nu statusvärdet frånos.waitpid()
på barnprocessen.
Exempel¶
Följande program fungerar som Unix-kommandot script(1) och använder en pseudoterminal för att registrera alla in- och utdata i en terminalsession i ett ”typescript”.
import argparse
import os
import pty
import sys
import time
parser = argparse.ArgumentParser()
parser.add_argument('-a', dest='append', action='store_true')
parser.add_argument('-p', dest='use_python', action='store_true')
parser.add_argument('filename', nargs='?', default='typescript')
options = parser.parse_args()
shell = sys.executable if options.use_python else os.environ.get('SHELL', 'sh')
filename = options.filename
mode = 'ab' if options.append else 'wb'
with open(filename, mode) as script:
def read(fd):
data = os.read(fd, 1024)
script.write(data)
return data
print('Script started, file is', filename)
script.write(('Script started on %s\n' % time.asctime()).encode())
pty.spawn(shell, read)
script.write(('Script done on %s\n' % time.asctime()).encode())
print('Script done, file is', filename)