Om du är en Linux-användare, kommer du säkert att uppskatta kraften i skal-kommandon.
Och om du arbetar med Python, kanske du har utforskat möjligheterna till automatisering. Det är ett utmärkt sätt att spara tid. Du kanske även har använt bash-skript för att automatisera olika uppgifter.
Python är ofta ett mer smidigt verktyg för skriptskrivning jämfört med bash. Hantering av Python-skript upplevs som enklare än att underhålla bash-skript, speciellt när de blir mer komplexa.
Men, vad händer om du redan har befintliga bash-skript som du vill integrera med din Python-kod?
Finns det en möjlighet att köra bash-kommandon och skript direkt inifrån Python?
Absolut, Python erbjuder en inbyggd modul, `subprocess`, som är utformad för att hantera just detta – att köra kommandon och skript i Python-skript. Låt oss undersöka närmare hur man kan använda den för att exekvera bash-kommandon och skript.
Exekvera bash-kommandon
Som du kanske redan har gissat, är det `subprocess`-modulen som vi vänder oss till för att köra bash-kommandon och skript. Modulen tillhandahåller olika metoder och klasser för detta ändamål.
I huvudsak finns det en metod och en klass som är viktiga att känna till inom `subprocess`-modulen: `run` och `Popen`. Båda dessa gör det möjligt för oss att exekvera bash-kommandon direkt i våra Python-skript. Låt oss granska dem var för sig.
`subprocess.run()`
Metoden `subprocess.run()` accepterar en lista av strängar som ett positionsargument. Detta argument är obligatoriskt och innehåller själva bash-kommandot och eventuella argument till kommandot. Det första elementet i listan är namnet på kommandot, medan de övriga elementen är argumenten som skickas till kommandot.
Låt oss titta på ett enkelt exempel.
import subprocess subprocess.run(["ls"])
Det ovanstående skriptet listar alla objekt i den aktuella arbetskatalogen där skriptet finns. I det här fallet har kommandot inga extra argument. Vi har endast angett själva bash-kommandot. Men vi kan lika gärna lägga till argument till `ls`-kommandot, som till exempel `-l`, `-a`, `-la` osv.
Här är ett exempel som använder argument till kommandot:
import subprocess subprocess.run(["ls", "-la"])
Det här kommandot listar alla filer, inklusive dolda filer, och visar även filernas rättigheter. Genom argumentet `la` specificerar vi att vi vill ha detaljerad information och att även dolda filer ska inkluderas.
Ibland kan misstag ske när vi skriver kommandona. Fel kommer att dyka upp i takt med misstagen. Vad händer om vi vill fånga dessa fel och använda dem senare? Det är möjligt med hjälp av sökordsargumentet `stderr`.
Låt oss se på ett exempel:
import subprocess result = subprocess.run(["cat", "sample.txt"], stderr=subprocess.PIPE, text=True) print(result.stderr)
Se till att filen med namnet `sample.txt` inte finns i din arbetskatalog. Värdet på nyckelordsargumentet `stderr` är `PIPE`, vilket gör att felet returneras i ett objekt. Vi kan sedan komma åt det senare med samma namn. Och nyckelordsargumentet `text` talar om för Python att utdata ska tolkas som en sträng.
På samma sätt kan vi även fånga resultatet av kommandot med hjälp av nyckelordsargumentet `stdout`.
import subprocess result = subprocess.run(["echo", "Hello, World!"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) print(result.stdout)
`subprocess.run()` – Inmatning
Du kan mata in data till kommandona med hjälp av nyckelordsargumentet `input`. Vi kommer att ange inmatningen i strängformat. Därför måste vi också ställa in nyckelordsargumentet `text` till `True`, eftersom det annars hanteras som bytes.
Här är ett exempel:
import subprocess subprocess.run(["python3", "add.py"], text=True, input="2 3")
I programmet ovan kommer Python-skriptet `add.py` att ta två siffror som inmatning. Vi skickar inmatningen till Python-skriptet med hjälp av nyckelordsargumentet `input`.
`subprocess.Popen()`
Klassen `subprocess.Popen()` är mer avancerad än metoden `subprocess.run()`. Den ger fler möjligheter för att hantera exekvering av kommandona. Vi kommer att skapa en instans av `subprocess.Popen()` och använda den för att utföra olika operationer, som att få information om kommandoexekveringens status, hämta utdata, ge inmatning, etc.
Det finns ett flertal metoder för klassen `subprocess.Popen()` som är viktiga att känna till. Låt oss gå igenom dem en efter en, med tillhörande kodexempel.
`wait()`
Denna metod används för att pausa exekveringen av Python-skriptet tills det anropade kommandot har slutfört sitt arbete. Följande rader i skriptet kommer inte att köras förrän kommandot, vars exekvering inväntas med `wait()`, är färdigt. Se exemplet nedan:
import subprocess process = subprocess.Popen(["ls", "-la"]) print("Färdig!")
Om du kör koden ovan kommer du att märka att meddelandet ”Färdig!” skrivs ut innan kommandot är färdigt. Vi kan undvika det här beteendet genom att använda metoden `wait()`. Låt oss vänta på att kommandot ska avslutas:
import subprocess process = subprocess.Popen(["ls", "-la"]) process.wait() print("Färdig!")
Om du nu ser utdata från koden, inser du att `wait()` fungerar som den ska. Utskriftssatsen exekveras efter att kommandot har slutförts.
`communicate()`
Metoden `communicate` används för att hämta utdata och fel från kommandot, samt för att ge inmatning. Den returnerar en tupel som innehåller utdatan och eventuella fel. Låt oss se ett exempel:
import subprocess process = subprocess.Popen(["echo", "Hej, Världen!"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) result = process.communicate() print(result)
`subprocess.Popen()` – Inmatning
Vi kan inte skicka inmatning till klassen `Popen` direkt. Vi måste använda nyckelordsargumentet `stdin` för att ge inmatning till kommandot. Instansen av klassen `Popen` kommer då att förse oss med ett `stdin`-objekt. Detta objekt har en metod som heter `write` som används för att skicka inmatning till kommandot.
Som tidigare nämnt, accepterar `stdin` som standard inmatning i byte-format. Så glöm inte att ställa in nyckelordsargumentet `text` till `True` när du skapar instansen av `Popen`.
Låt oss se ett exempel:
import subprocess process = subprocess.Popen(["python3", "add.py"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) process.stdin.write("2 3") process.stdin.close() print(process.stdout.read())
`poll()`
Metoden `poll` används för att kontrollera om kommandots exekvering är klar eller inte. Den här metoden returnerar `None` om kommandot fortfarande körs. Låt oss se ett exempel:
import subprocess process = subprocess.Popen(['ping', '-c 5', 'geekflare.com'], stdout=subprocess.PIPE, text=True) while True: output = process.stdout.readline() if output: print(output.strip()) result = process.poll() if result is not None: break
I koden ovan har vi använt kommandot `ping` med 5 förfrågningar. Det finns en oändlig loop som fortsätter tills kommandots exekvering är klar. Vi har använt metoden `poll` för att kontrollera statusen på kommandoexekveringen. Om metoden `poll` returnerar ett annat värde än `None`, betyder det att exekveringen är klar. Då avbryts den oändliga loopen.
Exekvera Bash-skript
Vi har sett två sätt att utföra kommandon. Låt oss nu se hur man kan köra bash-skript i Python-skript.
Modulen `subprocess` innehåller en metod som kallas `call`. Denna metod används för att köra bash-skript. Metoden returnerar utgångskoden från bash-skriptet. Standard utgångskoden för bash-skript är 0. Låt oss se ett exempel.
Skapa ett bash-skript med namnet `practice.sh` enligt följande:
#!/bin/bash echo "Hej, Världen!" exit 1
Skriv nu ett Python-skript och kör bash-skriptet ovan:
import subprocess exit_code = subprocess.call('./practice.sh') print(exit_code)
När du kör Python-skriptet ovan kommer du att få följande utdata:
Hej, Världen! 1
Slutsats
Vi har nu undersökt hur man kör bash-kommandon och skript i Python. Du kan använda dessa tekniker för att automatisera dina arbetsflöden mer effektivt.
Lycka till med kodningen! 👨💻