shlex — Enkel lexikal analys

Källkod: Lib/shlex.py


Klassen shlex gör det enkelt att skriva lexikala analysatorer för enkla syntaxer som liknar den i Unix-skalet. Detta är ofta användbart för att skriva minilanguages (till exempel i körkontrollfiler för Python-program) eller för att analysera citerade strängar.

Modulen shlex definierar följande funktioner:

shlex.split(s, comments=False, posix=True)

Dela upp strängen s med shell-liknande syntax. Om comments är False (standard), inaktiveras tolkningen av kommentarer i den angivna strängen (attributet commenters i shlex-instansen sätts till den tomma strängen). Denna funktion arbetar i POSIX-läge som standard, men använder icke-POSIX-läge om argumentet posix är falskt.

Ändrad i version 3.12: Att ange None för s-argumentet ger nu upphov till ett undantag, istället för att läsa sys.stdin.

shlex.join(split_command)

Sammanfoga symbolerna i listan split_command och returnera en sträng. Denna funktion är inversen av split().

>>> from shlex import join
>>> print(join(['echo', '-n', 'Multiple words']))
echo -n 'Multiple words'

Det returnerade värdet är shell-escaped för att skydda mot injektionssårbarheter (se quote()).

Tillagd i version 3.8.

shlex.quote(s)

Returnerar en shell-escaped version av strängen s. Det returnerade värdet är en sträng som säkert kan användas som en token i en kommandorad i ett skal, i de fall där du inte kan använda en lista.

Varning

Modulen shlex är endast avsedd för Unix-skal.

Funktionen quote() garanteras inte vara korrekt i skal som inte är kompatibla med POSIX eller i skal från andra operativsystem, t.ex. Windows. Om kommandon som citeras av den här modulen körs i sådana skal kan det leda till en sårbarhet genom kommandoinjektion.

Överväg att använda funktioner som skickar kommandoparametrar med listor, t.ex. subprocess.run() med shell=False.

Detta idiom skulle vara osäkert:

>>> filename = 'somefile; rm -rf ~'
>>> command = 'ls -l {}'.format(filename)
>>> print(command)  # executed by a shell: boom!
ls -l somefile; rm -rf ~

quote() låter dig täppa till säkerhetshålet:

>>> from shlex import quote
>>> command = 'ls -l {}'.format(quote(filename))
>>> print(command)
ls -l 'somefile; rm -rf ~'
>>> remote_command = 'ssh home {}'.format(quote(command))
>>> print(remote_command)
ssh home 'ls -l '"'"'somefile; rm -rf ~'"'"''

Citeringen är kompatibel med UNIX-shell och med split():

>>> from shlex import split
>>> remote_command = split(remote_command)
>>> remote_command
['ssh', 'home', "ls -l 'somefile; rm -rf ~'"]
>>> command = split(remote_command[-1])
>>> command
['ls', '-l', 'somefile; rm -rf ~']

Tillagd i version 3.3.

Modulen shlex definierar följande klass:

class shlex.shlex(instream=None, infile=None, posix=False, punctuation_chars=False)

En shlex-instans eller underklass-instans är ett lexikaliskt analysobjekt. Initialiseringsargumentet, om det finns, anger varifrån tecken ska läsas. Det måste vara ett fil-/strömliknande objekt med metoderna read() och readline(), eller en sträng. Om inget argument anges kommer indata att hämtas från sys.stdin. Det andra valfria argumentet är en filnamnssträng som anger det initiala värdet för attributet infile. Om argumentet instream utelämnas eller är lika med sys.stdin, är detta andra argument standardvärdet ”stdin”. Argumentet posix definierar driftläget: när posix inte är sant (standard), kommer shlex-instansen att fungera i kompatibilitetsläge. I POSIX-läge kommer shlex att försöka ligga så nära POSIX-skalets parsningsregler som möjligt. Argumentet punctuation_chars ger ett sätt att göra beteendet ännu närmare hur riktiga skal parsar. Detta kan anta ett antal värden: standardvärdet, False, bevarar det beteende som ses under Python 3.5 och tidigare. Om det sätts till True, ändras tolkningen av tecknen ();<>|&: varje serie av dessa tecken (som betraktas som skiljetecken) returneras som en enda token. Om den är inställd på en icke-tom sträng av tecken, kommer dessa tecken att användas som skiljetecken. Alla tecken i attributet wordchars som förekommer i punctuation_chars kommer att tas bort från wordchars. Se Förbättrad kompatibilitet med skal för mer information. punctuation_chars kan endast ställas in när shlex instansen skapas och kan inte ändras senare.

Ändrad i version 3.6: Parametern punctuation_chars har lagts till.

Se även

Modul configparser

Parser för konfigurationsfiler som liknar Windows .ini-filer.

shlex Objekt

En shlex-instans har följande metoder:

shlex.get_token()

Returnerar en token. Om tokens har staplats med hjälp av push_token(), plocka en token från stapeln. I annat fall, läs en från inmatningsströmmen. Om läsningen stöter på ett omedelbart filslut returneras eof (den tomma strängen ('') i icke-POSIX-läge och None i POSIX-läge).

shlex.push_token(str)

Lägg argumentet på token-stacken.

shlex.read_token()

Läs en rå token. Ignorera pushback-stacken och tolka inte källförfrågningar. (Detta är normalt inte en användbar ingångspunkt och dokumenteras här endast för fullständighetens skull)

shlex.sourcehook(filename)

När shlex upptäcker en källa (se source nedan) får denna metod följande token som argument, och förväntas returnera en tupel bestående av ett filnamn och ett öppet filliknande objekt.

Normalt tar den här metoden först bort alla citattecken från argumentet. Om resultatet är ett absolut sökvägsnamn, eller om det inte fanns någon tidigare källbegäran, eller om den tidigare källan var en ström (t.ex. sys.stdin), lämnas resultatet i fred. I annat fall, om resultatet är ett relativt sökvägsnamn, läggs katalogdelen av namnet på filen omedelbart före det i källinkluderingsstapeln till (detta beteende liknar det sätt på vilket C-förprocessorn hanterar #include "file.h").

Resultatet av manipuleringarna behandlas som ett filnamn och returneras som den första komponenten i tupeln, med open() anropad för att ge den andra komponenten. (Obs: detta är omvänd ordning på argumenten vid initiering av instanser!)

Denna hook är exponerad så att du kan använda den för att implementera katalogsökvägar, tillägg av filändelser och andra namnrymdshack. Det finns ingen motsvarande ”close”-hook, men en shlex-instans kommer att anropa close()-metoden för den hämtade inmatningsströmmen när den returnerar EOF.

För mer explicit kontroll av källans stapling, använd metoderna push_source() och pop_source().

shlex.push_source(newstream, newfile=None)

Skjuter upp en inmatningskällström på inmatningsstapeln. Om filnamnsargumentet anges kommer det senare att vara tillgängligt för användning i felmeddelanden. Detta är samma metod som används internt av metoden sourcehook().

shlex.pop_source()

Plocka bort den senast inmatade källan från inmatningsstapeln. Detta är samma metod som används internt när lexaren når EOF på en staplad inmatningsström.

shlex.error_leader(infile=None, lineno=None)

Denna metod genererar en felmeddelandeledare i formatet för en Unix C-kompilators feletikett; formatet är '"%s", rad %d: ', där %s ersätts med namnet på den aktuella källfilen och %d med det aktuella radnumret för inmatningen (de valfria argumenten kan användas för att åsidosätta dessa).

Detta är ett sätt att uppmuntra shlex-användare att generera felmeddelanden i ett standardformat som kan tolkas av Emacs och andra Unix-verktyg.

Instanser av underklasserna shlex har några offentliga instansvariabler som antingen styr den lexikala analysen eller kan användas för felsökning:

shlex.commenters

Den teckensträng som identifieras som början på en kommentar. Alla tecken från kommentarens början till slutet av raden ignoreras. Inkluderar bara '#' som standard.

shlex.wordchars

Den teckensträng som kommer att ackumuleras till flerteckentokens. Som standard ingår alla alfanumeriska ASCII-tecken och understreck. I POSIX-läge ingår även de accentuerade tecknen i Latin-1-uppsättningen. Om punctuation_chars inte är tomt, kommer tecknen ~-./*?=, som kan förekomma i filnamnsspecifikationer och kommandoradsparametrar, också att inkluderas i detta attribut, och alla tecken som förekommer i punctuation_chars kommer att tas bort från wordchars om de förekommer där. Om whitespace_split är satt till True, kommer detta inte att ha någon effekt.

shlex.whitespace

Tecken som ska betraktas som blanksteg och hoppas över. Blanksteg avgränsar tokens. Som standard ingår mellanslag, tabb, radmatning och carriage-return.

shlex.escape

Tecken som kommer att betraktas som escape. Detta kommer endast att användas i POSIX-läge, och inkluderar bara '\' som standard.

shlex.quotes

Tecken som kommer att betraktas som strängcitat. Token ackumuleras tills samma citattecken påträffas igen (olika citattyper skyddar alltså varandra som i skalet.) Som standard ingår ASCII enkla och dubbla citattecken.

shlex.escapedquotes

Tecken i quotes som kommer att tolka escape-tecken definierade i escape. Detta används endast i POSIX-läge och inkluderar bara '"' som standard.

shlex.whitespace_split

Om True, kommer tokens endast att delas upp i blanksteg. Detta är användbart, till exempel, för att analysera kommandorader med shlex, och få tokens på ett liknande sätt som skalargument. När det används i kombination med punctuation_chars, kommer tokens att delas upp på blanksteg utöver dessa tecken.

Ändrad i version 3.8: Attributet punctuation_chars har gjorts kompatibelt med attributet whitespace_split.

shlex.infile

Namnet på den aktuella indatafilen, som ursprungligen ställdes in vid klassens instantiering eller staplades av senare källförfrågningar. Det kan vara användbart att undersöka detta när man konstruerar felmeddelanden.

shlex.instream

Den inmatningsström från vilken denna shlex-instans läser tecken.

shlex.source

Detta attribut är None som standard. Om du tilldelar det en sträng kommer den strängen att tolkas som en inkluderingsbegäran på lexikal nivå, på samma sätt som nyckelordet ource i olika skal. Det vill säga, den omedelbart följande token öppnas som ett filnamn och indata tas från den strömmen till EOF, varvid close()-metoden för den strömmen anropas och indatakällan åter blir den ursprungliga indataströmmen. Källförfrågningar kan staplas på valfritt antal nivåer.

shlex.debug

Om det här attributet är numeriskt och 1 eller mer, kommer en shlex-instans att skriva ut utförliga förloppsdata om sitt beteende. Om du behöver använda detta kan du läsa modulens källkod för att få mer information.

shlex.lineno

Källans radnummer (antal nya rader som hittills setts plus ett).

shlex.token

Buffert för token. Det kan vara användbart att undersöka detta när man fångar upp undantag.

shlex.eof

Token som används för att avgöra slutet på filen. Detta kommer att sättas till den tomma strängen ('') i icke-POSIX-läge och till None i POSIX-läge.

shlex.punctuation_chars

A read-only property. Characters that will be considered punctuation. Runs of punctuation characters will be returned as a single token. However, note that no semantic validity checking will be performed: for example, ’>>>’ could be returned as a token, even though it may not be recognised as such by shells.

Tillagd i version 3.6.

Parsing-regler

Vid drift i icke-POSIX-läge kommer shlex att försöka följa följande regler.

  • Citationstecken identifieras inte inom ord (Do"Not"Separate tolkas som det enskilda ordet Do"Not"Separate);

  • Escape-tecken identifieras inte;

  • Om tecken omsluts av citattecken bevaras det bokstavliga värdet av alla tecken inom citattecknen;

  • Avslutande citat separerar ord ("Do"Separate tolkas som "Do" och Separate);

  • Om whitespace_split är False, kommer alla tecken som inte är deklarerade som ordtecken, blanksteg eller citat att returneras som en token med ett tecken. Om det är True, kommer shlex endast att dela ord i blanksteg;

  • EOF signaleras med en tom sträng ('');

  • Det är inte möjligt att analysera tomma strängar, inte ens om de är citerade.

I POSIX-läge kommer shlex att försöka följa följande parsingregler.

  • Citationstecken tas bort och separerar inte ord ("Do"Not"Separate" tolkas som det enskilda ordet DoNotSeparate);

  • Icke-citerade escape-tecken (t.ex. '\') bevarar det bokstavliga värdet av nästa tecken som följer;

  • Om tecken omsluts av citattecken som inte ingår i escapedquotes (t.ex. "'") bevaras det bokstavliga värdet av alla tecken inom citattecknen;

  • Om tecken omsluts av citattecken som ingår i escapedquotes (t.ex. '"') bevaras det bokstavliga värdet av alla tecken inom citattecknen, med undantag för de tecken som nämns i escape. Escape-tecknen behåller sin speciella betydelse endast när de följs av det använda citatet eller själva escape-tecknet. I annat fall betraktas escape-tecknet som ett normalt tecken.

  • EOF signaleras med ett None-värde;

  • Kvoterade tomma strängar ('') är tillåtna.

Förbättrad kompatibilitet med skal

Tillagd i version 3.6.

Klassen shlex ger kompatibilitet med den parsning som utförs av vanliga Unix-skal som bash, dash och sh. För att dra nytta av denna kompatibilitet, ange argumentet punctuation_chars i konstruktören. Standardvärdet är False, vilket bevarar beteendet före 3.6. Om det sätts till True ändras dock parsningen av tecknen ();<>|&: varje serie av dessa tecken returneras som en enda token. Även om detta inte är en fullständig parser för skal (vilket skulle vara utanför ramen för standardbiblioteket, med tanke på den mångfald av skal som finns), gör det att du kan utföra bearbetning av kommandorader enklare än du annars skulle kunna. För att illustrera kan du se skillnaden i följande utdrag:

>>> import shlex
>>> text = "a && b; c && d || e; f >'abc'; (def \"ghi\")"
>>> s = shlex.shlex(text, posix=True)
>>> s.whitespace_split = True
>>> list(s)
['a', '&&', 'b;', 'c', '&&', 'd', '||', 'e;', 'f', '>abc;', '(def', 'ghi)']
>>> s = shlex.shlex(text, posix=True, punctuation_chars=True)
>>> s.whitespace_split = True
>>> list(s)
['a', '&&', 'b', ';', 'c', '&&', 'd', '||', 'e', ';', 'f', '>', 'abc', ';',
'(', 'def', 'ghi', ')']

Naturligtvis kommer tokens att returneras som inte är giltiga för skal, och du måste implementera dina egna felkontroller på de returnerade tokens.

I stället för att skicka True som värde för parametern punctuation_chars kan du skicka en sträng med specifika tecken som används för att avgöra vilka tecken som utgör skiljetecken. Till exempel:

>>> import shlex
>>> s = shlex.shlex("a && b || c", punctuation_chars="|")
>>> list(s)
['a', '&', '&', 'b', '||', 'c']

Anteckning

När punctuation_chars anges, utökas attributet wordchars med tecknen ~-./*?=. Det beror på att dessa tecken kan förekomma i filnamn (inklusive jokertecken) och kommandoradsargument (t.ex. --color=auto). Därav:

>>> import shlex
>>> s = shlex.shlex('~/a && b-c --color=auto || d *.py?',
...                 punctuation_chars=True)
>>> list(s)
['~/a', '&&', 'b-c', '--color=auto', '||', 'd', '*.py?']

För att matcha skalet så nära som möjligt rekommenderas dock att man alltid använder posix och whitespace_split när man använder punctuation_chars, vilket gör att wordchars helt försvinner.

För bästa effekt bör punctuation_chars ställas in tillsammans med posix=True. (Observera att posix=False är standard för shlex)