ෂෙල් විධානය ක්‍රියාත්මක කිරීම සහ ප්‍රතිදානය අල්ලා ගැනීම


946

මට අවශ්‍ය ශ්‍රිතයක් ලිවීමට අවශ්‍ය වන අතර එය ෂෙල් විධානයක් ක්‍රියාත්මක කර එහි ප්‍රතිදානය දාමයක් ලෙස ලබා දෙනු ඇත. එය දෝෂයක් හෝ සාර්ථක පණිවිඩයක් වේ. මට අවශ්‍ය වන්නේ විධාන රේඛාව සමඟ මා ලබාගත් ප්‍රති result ලයම ලබා ගැනීමයි.

එවැනි දෙයක් කරන කේත උදාහරණයක් වන්නේ කුමක් ද?

උදාහරණයක් වශයෙන්:

def run_command(cmd):
    # ??????

print run_command('mysqladmin create test -uroot -pmysqladmin12')
# Should output something like:
# mysqladmin: CREATE DATABASE failed; error: 'Can't create database 'test'; database exists'

2
jfs

Answers:


1198

මෙම ප්‍රශ්නයට පිළිතුර රඳා පවතින්නේ ඔබ භාවිතා කරන පයිතන් අනුවාදය මත ය. සරලම ප්‍රවේශය නම් subprocess.check_outputශ්‍රිතය භාවිතා කිරීමයි :

>>> subprocess.check_output(['ls', '-l'])
b'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

check_outputආදාන ලෙස තර්ක පමණක් ගන්නා තනි වැඩසටහනක් ක්‍රියාත්මක කරයි. 1 එය මුද්‍රණය කළ ආකාරයටම ප්‍රති result ලය ලබා දෙයි stdout. ඔබට ආදානය ලිවීමට අවශ්‍ය නම් stdin, runහෝ Popenඅංශ වෙත ඉදිරියට යන්න . ඔබට සංකීර්ණ ෂෙල් විධාන ක්‍රියාත්මක කිරීමට අවශ්‍ය නම් shell=True, මෙම පිළිතුර අවසානයේ ඇති සටහන බලන්න .

මෙම check_outputකාර්යය තවමත් පුළුල් භාවිතයේ පවතින (2.7+) පයිතන්ගේ සියලුම සංස්කරණ වල ක්‍රියා කරයි. 2 නමුත් වඩාත් මෑත සංස්කරණ සඳහා, එය තවදුරටත් නිර්දේශිත ප්‍රවේශය නොවේ.

පයිතන්ගේ නවීන අනුවාදයන් (3.5 හෝ ඊට වැඩි): run

ඔබ පයිතන් 3.5 හෝ ඊට වැඩි භාවිතා කරන්නේ නම් සහ පසුපසට අනුකූලතාවය අවශ්‍ය නොවේ නම් , නව runකාර්යය නිර්දේශ කෙරේ. එය subprocessමොඩියුලය සඳහා ඉතා සාමාන්‍ය, ඉහළ මට්ටමේ API එකක් සපයයි . වැඩසටහනක ප්‍රතිදානය ග්‍රහණය කර ගැනීම සඳහා, subprocess.PIPEධජය stdoutයතුරු පද තර්කයට යොමු කරන්න. ඉන්පසු stdoutආපසු ලබා දුන් CompletedProcessවස්තුවේ ගුණාංගයට ප්‍රවේශ වන්න :

>>> import subprocess
>>> result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE)
>>> result.stdout
b'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

ප්‍රතිලාභ අගය bytesවස්තුවකි, එබැවින් ඔබට නිසි නූලක් අවශ්‍ය නම් ඔබට decodeඑය අවශ්‍ය වේ . කැඳවූ ක්‍රියාවලිය උපකල්පනය කිරීමෙන් යූටීඑෆ් -8 කේතනය කළ නූලක් ලැබේ:

>>> result.stdout.decode('utf-8')
'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

මේ සියල්ල එක් ලයිනර් එකකට සම්පීඩනය කළ හැකිය:

>>> subprocess.run(['ls', '-l'], stdout=subprocess.PIPE).stdout.decode('utf-8')
'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

ඔබට ක්‍රියාවලියට ආදානය යැවීමට අවශ්‍ය නම් stdin, bytesවස්තුවක් inputයතුරු පදයට යොමු කරන්න:

>>> cmd = ['awk', 'length($0) > 5']
>>> input = 'foo\nfoofoo\n'.encode('utf-8')
>>> result = subprocess.run(cmd, stdout=subprocess.PIPE, input=input)
>>> result.stdout.decode('utf-8')
'foofoo\n'

සමත් වීමෙන් stderr=subprocess.PIPE(ග්‍රහණය කර ගැනීමට result.stderr) හෝ stderr=subprocess.STDOUT( result.stdoutනිත්‍ය ප්‍රතිදානය සමඟ ග්‍රහණය කර ගැනීමෙන් ) ඔබට දෝෂ අල්ලා ගත හැකිය . ආරක්ෂාව ගැන සැලකිලිමත් නොවන විට, shell=Trueපහත සටහන් වල විස්තර කර ඇති පරිදි සම්මත කිරීමෙන් ඔබට වඩාත් සංකීර්ණ ෂෙල් විධාන ක්‍රියාත්මක කළ හැකිය .

පැරණි දේවල් කරන ක්‍රමයට සාපේක්ෂව මෙය ටිකක් සංකීර්ණ බවක් එක් කරයි. නමුත් එය ගෙවීම වටී යැයි මම සිතමි: දැන් ඔබට runශ්‍රිතය සමඟ පමණක් කළ යුතු ඕනෑම දෙයක් කළ හැකිය .

පයිතන්ගේ පැරණි අනුවාදයන් (2.7-3.4): check_output

ඔබ පයිතන්ගේ පැරණි අනුවාදයක් භාවිතා කරන්නේ නම් හෝ පසුපසට අනුකූලතාවයක් අවශ්‍ය නම්, check_outputඉහත විස්තර කර ඇති පරිදි ඔබට ශ්‍රිතය භාවිතා කළ හැකිය . පයිතන් 2.7 සිට එය ලබා ගත හැකිය.

subprocess.check_output(*popenargs, **kwargs)  

එය Popen(පහත බලන්න) හා සමාන තර්ක ගෙන, වැඩසටහනේ ප්‍රතිදානය අඩංගු නූලක් ලබා දෙයි. මෙම පිළිතුරේ ආරම්භයට වඩාත් සවිස්තරාත්මක භාවිත උදාහරණයක් ඇත. Python 3.5 හා වැඩි දී, check_outputක්රියාත්මක කිරීමට හා සමාන වේ runසමග check=Trueහා stdout=PIPE, හා පමණක් නැවත stdoutබලමු ඩේටා.

ඔබ සමත් හැකි stderr=subprocess.STDOUTනමුත් python, සමහර සංස්කරණවල පසුකර - එම වරද පණිවිඩ නැවත නිෂ්පාදනය ඇතුළත් තහවුරු කිරීම සඳහා stderr=subprocess.PIPEකිරීමට check_outputහැකි හේතුවක් ඩෙඩ්ලොක්ස් . ආරක්ෂාව ගැන සැලකිලිමත් නොවන විට, shell=Trueපහත සටහන් වල විස්තර කර ඇති පරිදි සම්මත කිරීමෙන් ඔබට වඩාත් සංකීර්ණ ෂෙල් විධාන ක්‍රියාත්මක කළ හැකිය .

ඔබට ක්‍රියාවලියට නල මාර්ගයක් stderrයැවීමට හෝ ආදානය කිරීමට අවශ්‍ය නම් check_output, කාර්යය ඉටු නොවේ. බලන්න Popenඑම නඩුව පහත උදාහරණ.

පයිතන්ගේ සංකීර්ණ යෙදුම් සහ පැරණි අනුවාදයන් (2.6 සහ ඊට පහළ): Popen

ඔබට ගැඹුරු පසුගාමී අනුකූලතාවයක් අවශ්‍ය නම්, හෝ ඔබට සපයනවාට වඩා නවීන ක්‍රියාකාරිත්වයක් check_outputඅවශ්‍ය නම්, ඔබට සෘජුවම Popenවස්තූන් සමඟ වැඩ කිරීමට සිදුවනු ඇත , එමඟින් උපප්‍රොසෙස් සඳහා පහත් මට්ටමේ API සම්බන්ධ කරයි.

මෙම Popenඉදිකිරීමටත් එක්කෝ පිළිගන්නා එක් විධානයක් තර්ක තොරව, හෝ ලැයිස්තුවක් ලැයිස්තුවේ වෙනම අයිතමයක් ලෙස එක් එක්, විධාන අඩංගු ප්රථම අයිතමයක් ලෙස, තර්ක ඕනෑම අංකය සඳහන්. shlex.splitනිසි ලෙස ආකෘතිගත කළ ලැයිස්තු වලට නූල් විග්‍රහ කිරීමට උදව් කළ හැකිය. ක්‍රියාවලි IO කළමනාකරණය සහ පහත් මට්ටමේ වින්‍යාසය සඳහා Popenවස්තු විවිධ තර්ක රාශියක් පිළිගනී .

ආදානය යැවීම සහ ප්‍රතිදානය ග්‍රහණය කර ගැනීම communicateසෑම විටම පාහේ කැමති ක්‍රමයකි. මෙන්:

output = subprocess.Popen(["mycmd", "myarg"], 
                          stdout=subprocess.PIPE).communicate()[0]

හෝ

>>> import subprocess
>>> p = subprocess.Popen(['ls', '-a'], stdout=subprocess.PIPE, 
...                                    stderr=subprocess.PIPE)
>>> out, err = p.communicate()
>>> print out
.
..
foo

ඔබ සකසන්නේ නම් stdin=PIPE, communicateක්‍රියාවලිය හරහා දත්ත යැවීමට ද ඔබට ඉඩ දෙයි stdin:

>>> cmd = ['awk', 'length($0) > 5']
>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
...                           stderr=subprocess.PIPE,
...                           stdin=subprocess.PIPE)
>>> out, err = p.communicate('foo\nfoofoo\n')
>>> print out
foofoo

සටහන ආරොන් ශාලාව පිළිතුර ඇතැම් පද්ධති මත, ඔබ සකස් කර ගැනීමට අවශ්ය විය හැකි බවයි වන stdout, stderrහා stdinසියලු PIPE(හෝ DEVNULLලබා ගැනීමට) communicateසියලු වැඩ කිරීමට.

සමහර දුර්ලභ අවස්ථාවන්හිදී, ඔබට සංකීර්ණ, තත්‍ය කාලීන ප්‍රතිදානය අල්ලා ගැනීම අවශ්‍ය විය හැකිය. වර්ටෙක්ගේ පිළිතුරෙන් ඉදිරි මාවතක් යෝජනා කරයි, නමුත් communicateපරිස්සමින් භාවිතා නොකළහොත් හැර වෙනත් ක්‍රම අවහිර කිරීම් වලට ගොදුරු වේ.

ඉහත සියළු කාර්යයන් මෙන්ම, ආරක්ෂාව ගැන සැලකිලිමත් නොවන විට, සම්මත කිරීමෙන් ඔබට වඩාත් සංකීර්ණ ෂෙල් විධාන ක්‍රියාත්මක කළ shell=Trueහැකිය.

සටහන්

1. ෂෙල් විධාන ධාවනය කිරීම: shell=Trueතර්කය

සාමාන්යයෙන්, එක් එක් ඇමතුමක් run, check_outputහෝ Popenඉදිකිරීමටත් වූ ඉටු තනි වැඩසටහන . ඒ කියන්නේ විසිතුරු බෑෂ් විලාසිතාවේ පයිප්ප නැහැ. ඔබට සංකීර්ණ ෂෙල් විධාන ක්‍රියාත්මක කිරීමට අවශ්‍ය නම්, ඔබට සමත් විය හැකිය shell=True, එම කාර්යයන් තුනම සහාය වේ.

කෙසේ වෙතත්, එසේ කිරීමෙන් ආරක්ෂක ගැටළු මතු වේ. ඔබ සැහැල්ලු ස්ක්‍රිප්ටින් වලට වඩා වැඩි යමක් කරන්නේ නම්, ඔබට එක් එක් ක්‍රියාවලිය වෙන වෙනම ඇමතීමට වඩා හොඳ විය හැකි අතර, එක් එක් ප්‍රතිදානය ආදානය ලෙස ඊළඟට යැවීම වඩා හොඳය.

run(cmd, [stdout=etc...], input=other_output)

හෝ

Popen(cmd, [stdout=etc...]).communicate(other_output)

පයිප්ප කෙලින්ම සම්බන්ධ කිරීමට ඇති පෙළඹවීම ශක්තිමත් ය; එයට විරුද්ධ වන්න. එසේ නැත්නම්, ඔබ ඉඩ ඩෙඩ්ලොක්ස් බලන්න හෝ වැනි hacky දේවල් කරන්න වෙනවා මෙම .

2. යුනිකෝඩ් සලකා බැලීම

check_outputපයිතන් 2 හි නූලක් ලබා දෙයි, නමුත් පයිතන් 3 හි ඇති bytesවස්තුවක් ඔබ දැනටමත් නොමැති නම් යුනිකෝඩ් ගැන ඉගෙන ගැනීමට මොහොතක් ගත කිරීම වටී .


5
සමග දෙකම check_output()හා communicate()ඔබ මෙම ක්රියාවලිය සිදු වන තෙක් සමග, බලා සිටීමට සිදු poll()කරුණක් බැවින් ඒ ඔබ ප්රතිදානය යන්නේ. ඇත්ත වශයෙන්ම ඔබට අවශ්‍ය දේ රඳා පවතී.
vartec

2
මෙය අදාළ වන්නේ පයිතන්ගේ පසු සංස්කරණ වලට පමණක් දැයි විශ්වාස නැත, නමුත් විචල්‍යය මට outවර්ගය <class 'bytes'>විය. ප්‍රතිදානය නූලක් ලෙස ලබා ගැනීම සඳහා මුද්‍රණය කිරීමට පෙර එය විකේතනය කිරීමට මට සිදු විය:out.decode("utf-8")
පොලිමෙෂ්

1
passpar ඔබ සමත් වූ විට එය ඔබට ප්‍රයෝජනවත් shell=Trueනොවේද? එය මට වැඩ කරයි. ඔබ shlex.splitසමත් වූ විට ඔබට අවශ්‍ය නොවේ shell=True. shlex.splitෂෙල් නොවන විධාන සඳහා වේ. මම හිතන්නේ මම වතුර මඩ කරන නිසා මම ඒක ටිකක් එළියට ගන්නවා.
යවන්නා

2
පයිතන් 3.5+ මඟින් යතුරු පද තර්කයක් universal_newlines=Trueමඟින් පද්ධතියේ පෙරනිමි කේතීකරණයේ යුනිකෝඩ් නූල් ඉවත් කර ගැනීමට ඉඩ ලබා දේ. 3.7 දී මෙය වඩාත් සංවේදී ලෙස නම් කරන ලදී text=True.
ත්‍රිත්ව

2
පයිතන් 3.6+ සඳහා ඔබට භාවිතා encodingකිරීම subprocess.runවෙනුවට පරාමිතිය භාවිතා result.stdout.decode('utf-8')කළ හැකිය, ඔබට භාවිතා කළ හැකිය subprocess.run(['ls', '-l'], stdout=subprocess.PIPE, encoding='utf-8').
පියරේ

193

මෙය පහසුය, නමුත් ක්‍රියා කරන්නේ යුනික්ස් (සිග්වින් ද ඇතුළුව) සහ පයිතන් 2.7 මත පමණි.

import commands
print commands.getstatusoutput('wc -l file')

එය (return_value, output) සමඟ ටුපල් එකක් ලබා දෙයි.

Python2 සහ Python3 යන දෙකෙහිම ක්‍රියාත්මක වන විසඳුමක් සඳහා, subprocessඒ වෙනුවට මොඩියුලය භාවිතා කරන්න:

from subprocess import Popen, PIPE
output = Popen(["date"],stdout=PIPE)
response = output.communicate()
print response

31
දැන් ඉවත් කර ඇත, නමුත්
subprocess.check_output

22
මෙය යුනික්ස් විශේෂිත බව සලකන්න. එය වින්ඩෝස් හි අසාර්ථක වනු ඇත.
සිට්‍රැක්ස්

4
+1 මට පයිතන් 2.4 හි පැරණි අනුවාදය මත වැඩ කළ යුතු අතර මෙය බෙහෙවින් ප්‍රයෝජනවත් විය
javadba

1
PIPE මචන් යනු කුමක්ද යන්න සම්පූර්ණ කේතය පෙන්වන්න: subprocess.PIPE
කයිල් බ්‍රිඩන්ස්ටයින්

108

ඒ වගේ දෙයක්:

def runProcess(exe):    
    p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    while(True):
        # returns None while subprocess is running
        retcode = p.poll() 
        line = p.stdout.readline()
        yield line
        if retcode is not None:
            break

සටහන, මම stderr stdout වෙත හරවා යවන බව, එය ඔබට අවශ්‍ය දේම නොවිය හැකි නමුත් මට දෝෂ පණිවිඩද අවශ්‍ය වේ.

මෙම ශ්‍රිතය රේඛාව අනුව ඒවා ලැබෙන විට ලබා දෙයි (සාමාන්‍යයෙන් සමස්තයක් ලෙස ප්‍රතිදානය ලබා ගැනීම සඳහා උප ක්‍රියාවලිය අවසන් වන තෙක් ඔබ බලා සිටිය යුතුය).

ඔබේ නඩුවේ භාවිතය වනුයේ:

for line in runProcess('mysqladmin create test -uroot -pmysqladmin12'.split()):
    print line,

සිදුවිය හැකි අවහිරතා waitසහ callක්‍රියාකාරකම් වලක්වා ගැනීම සඳහා ප්‍රතිදානය ලබා ගැනීම සඳහා යම් ආකාරයක ක්‍රියාකාරී පුඩුවක් ක්‍රියාත්මක කිරීමට වග බලා ගන්න .
ඇන්ඩ්‍රේ කැරොන්

Il සිල්වර් ලයිට්: ඔබේ ක්‍රියාවලිය බොහෝ විට පරිශීලකයාගේ ආදානය බලාපොරොත්තුවෙන් සිටී. ආපසු පැමිණි විගසම එම ගොනුව PIPEසඳහා අගයක් ලබා දීමට stdinසහ වසා දැමීමට උත්සාහ කරන්න Popen.
ඇන්ඩ්‍රේ කැරොන්

4
-1: එය නම් අනන්ත පුඩුවක් වේ retcodeවේ 0. චෙක්පත විය යුතුය if retcode is not None. ඔබ හිස් නූල් ලබා නොදිය යුතුය (හිස් රේඛාවක් පවා අවම වශයෙන් එක් සංකේතයක් '\ n' වේ) : if line: yield line. p.stdout.close()අවසානයේ අමතන්න .
jfs

2
මම ls -L / dirname සමග කේතය උත්සාහ කල මෙම බහලුම තුල තවත් බොහෝ ගොනු ඇත අතර, එය ගොනු දෙකක් ලැයිස්තුගත පසු වැටෙයි
Vasilis

3
ufuenfundachtzig: සියලු ප්‍රතිදානය කියවන .readlines()තුරු නැවත නොඑනු ඇති අතර එම නිසා එය මතකයට නොගැලපෙන විශාල ප්‍රතිදානය සඳහා කැඩී යයි. if retcode is not None: yield from p.stdout.readlines(); break
උපසිරැසියෙන් ඉවත්වීමෙන්

69

වර්ටෙක්ගේ පිළිතුර සියලු පේළි කියවන්නේ නැත, එබැවින් මම එය කළ අනුවාදයක් කළෙමි:

def run_command(command):
    p = subprocess.Popen(command,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.STDOUT)
    return iter(p.stdout.readline, b'')

භාවිතය පිළිගත් පිළිතුරට සමාන වේ:

command = 'mysqladmin create test -uroot -pmysqladmin12'.split()
for line in run_command(command):
    print(line)

6
ඔබට return iter(p.stdout.readline, b'')while loop වෙනුවට භාවිතා කළ හැකිය
jfs

2
එය ඉතා සිසිල් භාවිතයකි, එය දැන සිටියේ නැත! මම කේතය යාවත්කාලීන කළා.
මැක්ස් එක්මන්

මට හොඳටම විශ්වාසයි stdout සියළුම ප්‍රතිදානයන් තබා ගන්නා බව, එය බෆරයක් සහිත ධාරා වස්තුවකි. පොපන් එකක් සම්පුර්ණ වූ පසු ඉතිරි සියලු නිමැවුම් ක්ෂය කිරීමට මම ඉතා සමාන තාක්‍ෂණයක් භාවිතා කරන අතර, මගේ නඩුවේදී, ප්‍රතිදානය සජීවීව ග්‍රහණය කර ගැනීම සඳහා ක්‍රියාත්මක කිරීමේදී ඡන්ද විමසීම () සහ කියවීම් භාවිතා කිරීම.
මැක්ස් එක්මන්

මගේ නොමඟ යවන ප්‍රකාශය මම ඉවත් කර ඇත්තෙමි. p.stdout.readline()ළමා ක්‍රියාවලිය දැනටමත් පිටව ගොස් තිබුණද ( p.poll()එසේ නොවේ None) හිස් නොවන පෙර බෆර් කළ ප්‍රතිදානය මට ලබා දිය හැකිය .
jfs

මෙම කේතය ක්‍රියා නොකරයි. මෙහි බලන්න stackoverflow.com/questions/24340877/…
thang

61

මෙය බොහෝ අවස්ථාවන්හිදී ක්‍රියාත්මක වන උපායශීලී නමුත් සුපිරි සරල විසඳුමකි:

import os
os.system('sample_cmd > tmp')
print open('tmp', 'r').read()

විධානයේ ප්‍රතිදානය සමඟ තාවකාලික ගොනුවක් (මෙන්න tmp) නිර්මාණය කර ඇති අතර එයින් ඔබට අවශ්‍ය ප්‍රතිදානය කියවිය හැකිය.

අදහස් වලින් අමතර සටහන: එක් වරක් රැකියාවක් කිරීමේදී ඔබට tmp ගොනුව ඉවත් කළ හැකිය. ඔබට මෙය කිහිප වතාවක් කිරීමට අවශ්‍ය නම්, tmp මකා දැමීමේ අවශ්‍යතාවයක් නොමැත.

os.remove('tmp')

5
අශෝභන නමුත් සුපිරි සරල + ඕනෑම තැනක වැඩ කරයි .. mktempමා අනුමාන කරන නූල් තත්වයන් තුළ එය ක්‍රියාත්මක කිරීමට එය ඒකාබද්ධ කළ හැකිය
ප්‍රකාශ් රාජගෝපාල්

2
සමහර විට වේගවත්ම ක්‍රමය os.remove('tmp')විය හැකි නමුත් එය "ගොනු රහිත" බවට පත් කිරීම වඩා හොඳය .
XuMuK

@XuMuK ඔබ එක් වරක් කරන රැකියාවක හරි. එය පුනරාවර්තන කාර්යයක් නම් සමහර විට මකා දැමීම අවශ්‍ය නොවේ
මෙහඩි සමන් බූයි

1
සමගාමී මුදල් සඳහා අයහපත්, නැවත ක්‍රියාත්මක කිරීමේ කාර්යයන් සඳහා අයහපත්, පද්ධතිය ආරම්භ වීමට පෙර තිබූ
ආකාරයටම නොපැමිණීම නරකයි

1
M 2 මියා නිසැකවම එය හේතුවක් නිසා පහසුය! සමගාමී කියවීම් සහ ලිවීම් සඳහා ගොනුව හවුල් මතකයක් ලෙස භාවිතා කිරීමට ඔබට අවශ්‍ය නම්, මෙය හොඳ තේරීමක් නොවේ. නමුත්, s.th. විධානයක ප්‍රතිදානය තිබීම වැනි (උදා: ls හෝ find or ...) එය හොඳ සහ වේගවත් තේරීමක් විය හැකිය. Btw ඔබට සරල ගැටලුවකට වේගවත් විසඳුමක් අවශ්‍ය නම් එය මා සිතන හොඳම දෙයයි. ඔබට නල මාර්ගයක් අවශ්‍ය නම්, උප ක්‍රියාවලිය ඔබ වෙනුවෙන් වඩාත් කාර්යක්ෂමව ක්‍රියා කරයි.
මෙහඩි සමන් බූයි

52

මට එකම ගැටලුවක් ඇති නමුත් මෙය සිදු කිරීමේ ඉතා සරල ක්‍රමයක් හදුනා ගත්තේය:

import subprocess
output = subprocess.getoutput("ls -l")
print(output)

එය උපකාරී වේ යැයි සිතමි

සටහන: මෙම විසඳුම Python3 හි subprocess.getoutput()ක්‍රියාත්මක නොවන බැවින් Python3 විශේෂිත වේ


5
එය විධානයෙහි ප්‍රතිදානය නූල් ලෙස ලබා දෙයි, ඒ තරම්ම සරලයි
azhar22k

1
ඇත්ත වශයෙන්ම, මුද්‍රණය යනු පයිතන් 2 හි ප්‍රකාශයකි. මෙය පයිතන් 3 පිළිතුරක් බව ඔබට තේරුම් ගත හැකිය.

2
මුද්‍රණ (ය) වලංගු පයිතන් 2. subprocess.getoutput නොවේ.
user48956

3
බොහෝ භාවිත අවස්ථා සඳහා, මිනිසුන්ට අවශ්‍ය වන්නේ මෙයයි: මතක තබා ගැනීම පහසුය, ප්‍රති results ල විකේතනය කිරීම අවශ්‍ය නොවේ. ස්තූතියි.
bwv549

1
ව්‍යතිරේක හැසිරවීම සඳහා දුර්වල සහායක් නොමැති ආරක්ෂක සහතිකයක් නොමැති උරුමයක් ලෙස මෙය පැහැදිලිවම සලකුණු කර ඇති බව සලකන්න .
යවන්නා

19

ඕනෑම ෂෙල් විධානයක් ක්‍රියාත්මක කිරීමට ඔබට පහත විධානයන් භාවිතා කළ හැකිය. මම ඒවා උබුන්ටු මත භාවිතා කර ඇත.

import os
os.popen('your command here').read()

සටහන: පයිතන් 2.6 සිට මෙය ඉවත් කරනු ලැබේ. දැන් ඔබ භාවිතා කළ යුතුය subprocess.Popen. පහත උදාහරණය

import subprocess

p = subprocess.Popen("Your command", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
print p.split("\n")

2
2.6 අනුවාදයෙන් ඉවත් කරන ලදි - docs.python.org/2/library/os.html#os.popen
ෆිලිපෝ

1
Ipp ෆිලිපෝ විටේල් ස්තූතියි. එය අවලංගු කර ඇති බව මා දැන සිටියේ නැත.
මුහම්මද් හසන්

1
Raspberrypi.stackexchange.com/questions/71547/… ට අනුව os.popen()පයිතන් 2.6 හි ඉවත් කර ඇත, නමුත් එය පයිතන් 3.x හි ක්ෂය නොකෙරේ , මන්ද 3.x දී එය ක්‍රියාත්මක subprocess.Popen()වේ.
JL

12

ඔබේ සැතපුම් ගණන වෙනස් විය හැකිය, මම පයිතන් 2.6.5 හි වින්ඩෝස් හි වර්ටෙක්ගේ විසඳුම සඳහා යවන්නාගේ භ්‍රමණය උත්සාහ කළෙමි, නමුත් මට දෝෂ ඇති වූ අතර වෙනත් විසඳුම් ක්‍රියාත්මක නොවීය. මගේ දෝෂය වූයේ : WindowsError: [Error 6] The handle is invalid.

මා බලාපොරොත්තු වූ ප්‍රතිදානය ආපසු ලබා ගැනීම සඳහා සෑම හසුරුවකටම PIPE පැවරිය යුතු බව මට පෙනී ගියේය - පහත සඳහන් දෑ මා වෙනුවෙන් වැඩ කළේය.

import subprocess

def run_command(cmd):
    """given shell command, returns communication tuple of stdout and stderr"""
    return subprocess.Popen(cmd, 
                            stdout=subprocess.PIPE, 
                            stderr=subprocess.PIPE, 
                            stdin=subprocess.PIPE).communicate()

මේ ආකාරයට අමතන්න, ( [0]ටුපල්හි පළමු අංගය ලැබේ, stdout):

run_command('tracert 11.1.0.1')[0]

වැඩිදුර ඉගෙනීමෙන් පසු, මට මෙම පයිප්ප තර්ක අවශ්‍ය යැයි මම විශ්වාස කරමි, මන්ද මම විවිධ හැන්ඩ්ල් භාවිතා කරන අභිරුචි පද්ධතියක වැඩ කරන බැවින් මට සියලු පන්ති සෘජුවම පාලනය කිරීමට සිදුවිය.

වින්ඩෝස් සමඟ කොන්සෝල උත්පතන නැවැත්වීමට, මෙය කරන්න:

def run_command(cmd):
    """given shell command, returns communication tuple of stdout and stderr"""
    # instantiate a startupinfo obj:
    startupinfo = subprocess.STARTUPINFO()
    # set the use show window flag, might make conditional on being in Windows:
    startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
    # pass as the startupinfo keyword argument:
    return subprocess.Popen(cmd,
                            stdout=subprocess.PIPE, 
                            stderr=subprocess.PIPE, 
                            stdin=subprocess.PIPE, 
                            startupinfo=startupinfo).communicate()

run_command('tracert 11.1.0.1')

1
සිත්ගන්නා සුළුය - මෙය වින්ඩෝස් දෙයක් විය යුතුය. මිනිසුන්ට සමාන දෝෂ ඇති වුවහොත් මම මේ වෙත යොමු කරන සටහනක් එක් කරමි.
යවන්නා

ඔබ පයිප්පයකින් ලිවීම / කියවීම නොකළහොත් DEVNULLඒ වෙනුවට භාවිතා කරන්න , subprocess.PIPEඑසේ නොමැතිනම් ඔබට ළමා ක්‍රියාවලිය එල්ලිය හැකිය.
jfs

11

පහත සඳහන් අවශ්‍යතා සමඟ එකම ගැටළුවේ තරමක් වෙනස් රසය මට තිබුණි:

  1. STDOUT පණිවිඩ STDOUT බෆරයේ (එනම් තත්‍ය කාලීනව) එකතු වන විට ඒවා ග්‍රහණය කර ආපසු එවන්න.
    • @vartec ජනක ඔහුගේ භාවිතය සහ 'අස්වැන්න' සමග මෙම Pythonically විසඳා
      මූල පදය ඉහත
  2. සියලුම STDOUT රේඛා මුද්‍රණය කරන්න ( STDOUT බෆරය සම්පූර්ණයෙන් කියවීමට පෙර ක්‍රියාවලිය පිටව ගියද )
  3. සීපීයූ චක්‍ර නාස්ති නොකරන්න
  4. උපසිරැසියෙහි ආපසු කේතය පරීක්ෂා කරන්න
  5. අපට ශුන්‍ය නොවන දෝෂ ආපසු කේතයක් ලැබෙන්නේ නම් STDERR (STDOUT වෙතින් වෙන් කරන්න) මුද්‍රණය කරන්න.

පහත දැක්වෙන කරුණු ඉදිරිපත් කිරීම සඳහා මම පෙර පිළිතුරු ඒකාබද්ධ කර වෙනස් කර ඇත්තෙමි.

import subprocess
from time import sleep

def run_command(command):
    p = subprocess.Popen(command,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE,
                         shell=True)
    # Read stdout from subprocess until the buffer is empty !
    for line in iter(p.stdout.readline, b''):
        if line: # Don't print blank lines
            yield line
    # This ensures the process has completed, AND sets the 'returncode' attr
    while p.poll() is None:                                                                                                                                        
        sleep(.1) #Don't waste CPU-cycles
    # Empty STDERR buffer
    err = p.stderr.read()
    if p.returncode != 0:
       # The run_command() function is responsible for logging STDERR 
       print("Error: " + str(err))

මෙම කේතය පෙර පිළිතුරු වලට සමානව ක්‍රියාත්මක වේ:

for line in run_command(cmd):
    print(line)

1
නින්ද (1) එකතු කිරීම CPU චක්‍ර නාස්ති නොකරන්නේ කෙසේදැයි පැහැදිලි කිරීමට ඔබට අවශ්‍යද?
Moataz Elmasry

2
p.poll()ඇමතුම් අතර නින්දක් නොමැතිව අපි දිගටම ඇමතුමක් ලබා දුන්නොත්, අපි මෙම ක්‍රියාව මිලියන ගණනක් ඇමතීමෙන් CPU චක්‍ර නාස්ති කරන්නෙමු. ඒ වෙනුවට, අපි ඊළඟ 1/10 තත්පරයට කරදර විය යුතු නැති බව මෙහෙයුම් පද්ධතියට පැවසීමෙන් අපගේ ලූපය “තෙරපීම” කරන්නෙමු, එවිට එයට වෙනත් කාර්යයන් කළ හැකිය. (අපගේ නින්ද ප්‍රකාශය අතිරික්තයක් බවට පත් කරමින් p.poll () ද නිදා ගැනීමට ඉඩ ඇත).
ඇල්ෆින්

5

සඳහා මූලික විධානය බෙදීම subprocess උපක්‍රමශීලී හා කරදරකාරී විය හැකිය.

shlex.split()ඔබට උදව් කිරීමට භාවිතා කරන්න .

නියැදි විධානය

git log -n 5 --since "5 years ago" --until "2 year ago"

කේතය

from subprocess import check_output
from shlex import split

res = check_output(split('git log -n 5 --since "5 years ago" --until "2 year ago"'))
print(res)
>>> b'commit 7696ab087a163e084d6870bb4e5e4d4198bdc61a\nAuthor: Artur Barseghyan...'

shlex.split()කේතය නොමැතිව පහත පරිදි පෙනෙනු ඇත

res = check_output([
    'git', 
    'log', 
    '-n', 
    '5', 
    '--since', 
    '5 years ago', 
    '--until', 
    '2 year ago'
])
print(res)
>>> b'commit 7696ab087a163e084d6870bb4e5e4d4198bdc61a\nAuthor: Artur Barseghyan...'

1
shlex.split()පහසුවකි, විශේෂයෙන් කවචයේ උපුටා දැක්වීම හරියටම ක්‍රියා කරන්නේ කෙසේදැයි ඔබ නොදන්නේ නම්; ['git', 'log', '-n', '5', '--since', '5 years ago', '--until', '2 year ago']ඔබ උපුටා දැක්වීම තේරුම් ගන්නේ නම් මෙම නූල අතින් ලැයිස්තුවට පරිවර්තනය කිරීම කිසිසේත් අපහසු නොවේ.
ත්‍රිත්ව

4

ඔබට විවිධ ගොනු වල ෂෙල් විධානයක් ක්‍රියාත්මක කිරීමට අවශ්‍ය නම්, මෙය මට උපක්‍රමයක් විය.

import os
import subprocess

# Define a function for running commands and capturing stdout line by line
# (Modified from Vartec's solution because it wasn't printing all lines)
def runProcess(exe):    
    p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    return iter(p.stdout.readline, b'')

# Get all filenames in working directory
for filename in os.listdir('./'):
    # This command will be run on each file
    cmd = 'nm ' + filename

    # Run the command and capture the output line by line.
    for line in runProcess(cmd.split()):
        # Eliminate leading and trailing whitespace
        line.strip()
        # Split the output 
        output = line.split()

        # Filter the output and print relevant lines
        if len(output) > 2:
            if ((output[2] == 'set_program_name')):
                print filename
                print line

සංස්කරණය කරන්න: ජේ. එෆ්. සෙබස්තියන්ගේ යෝජනාව සමඟ මැක්ස් පර්සන්ගේ විසඳුම දුටුවේය. ඉදිරියට ගොස් එය ඇතුළත් කර ඇත.


Popenඑක්කෝ නූලක් පිළිගනී, නමුත් පසුව ඔබට අවශ්‍යය shell=True, නැතහොත් තර්ක ලැයිස්තුවක් අවශ්‍ය ['nm', filename]වේ. මෙහි කිසිදු වටිනාකමක් ලබා නොදී කවචය සංකීර්ණත්වය එකතු කරන නිසා දෙවැන්න වඩාත් සුදුසුය. shell=Trueපෙනෙන විදිහට නූල් පසු කිරීම වින්ඩෝස් හි වැඩ කිරීම සිදු වන නමුත් එය ඊළඟ ඕනෑම පයිතන් අනුවාදයක වෙනස් විය හැකිය.
ත්‍රිත්ව

2

Andsenderle ට අනුව, ඔබ මා වැනි python3.6 භාවිතා කරන්නේ නම්:

def sh(cmd, input=""):
    rst = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, input=input.encode("utf-8"))
    assert rst.returncode == 0, rst.stderr.decode("utf-8")
    return rst.stdout.decode("utf-8")
sh("ls -a")

ඔබ විධානය bash ලෙස ක්‍රියාත්මක කරන ආකාරයටම ක්‍රියා කරයි


ඔබ මූලික වචන තර්ක නවීකරණය කරමින් check=True, universal_newlines=Trueසිටී. වෙනත් වචන වලින් කිවහොත්, subprocess.run()ඔබේ කේතය කරන සෑම දෙයක්ම දැනටමත් කරයි.
ත්‍රිත්ව

1

ඔබ subprocessපයිතන් මොඩියුලය භාවිතා කරන්නේ නම් , ඔබට STDOUT, STDERR සහ ආපසු විධාන කේතය වෙන වෙනම හැසිරවිය හැකිය. සම්පූර්ණ විධාන ඇමතුම් ක්‍රියාත්මක කිරීම සඳහා උදාහරණයක් ඔබට දැක ගත හැකිය. ඇත්ත වශයෙන්ම try..exceptඔබට අවශ්ය නම් එය දිගු කළ හැකිය .

පහත ශ්‍රිතය මඟින් STDOUT, STDERR සහ ප්‍රතිලාභ කේතය ලබා දෙන අතර එමඟින් ඔබට ඒවා වෙනත් ස්ක්‍රිප්ටයේ හැසිරවිය හැකිය.

import subprocess

def command_caller(command=None)
    sp = subprocess.Popen(command, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=False)
    out, err = sp.communicate()
    if sp.returncode:
        print(
            "Return code: %(ret_code)s Error message: %(err_msg)s"
            % {"ret_code": sp.returncode, "err_msg": err}
            )
    return sp.returncode, out, err

තවත් දුර්වල නැවත සකස් කිරීම subprocess.run(). රෝදය ප්‍රතිනිර්මාණය නොකරන්න.
ත්‍රිත්ව

0

උදා: ක්‍රියාත්මක කරන්න ('ls -ahl') හැකි ප්‍රතිලාභ තුනක් සහ හතරක් සහ මෙහෙයුම් පද්ධති වේදිකා වෙන්කර දැක්වීය:

  1. ප්‍රතිදානයක් නැත, නමුත් සාර්ථකව ධාවනය කරන්න
  2. හිස් රේඛාව ප්‍රතිදානය කරන්න, සාර්ථකව ක්‍රියාත්මක කරන්න
  3. ධාවනය අසාර්ථක විය
  4. යමක් ප්‍රතිදානය කරන්න, සාර්ථකව ක්‍රියාත්මක කරන්න

පහත ක්‍රියාකාරිත්වය

def execute(cmd, output=True, DEBUG_MODE=False):
"""Executes a bash command.
(cmd, output=True)
output: whether print shell output to screen, only affects screen display, does not affect returned values
return: ...regardless of output=True/False...
        returns shell output as a list with each elment is a line of string (whitespace stripped both sides) from output
        could be 
        [], ie, len()=0 --> no output;    
        [''] --> output empty line;     
        None --> error occured, see below

        if error ocurs, returns None (ie, is None), print out the error message to screen
"""
if not DEBUG_MODE:
    print "Command: " + cmd

    # https://stackoverflow.com/a/40139101/2292993
    def _execute_cmd(cmd):
        if os.name == 'nt' or platform.system() == 'Windows':
            # set stdin, out, err all to PIPE to get results (other than None) after run the Popen() instance
            p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
        else:
            # Use bash; the default is sh
            p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, executable="/bin/bash")

        # the Popen() instance starts running once instantiated (??)
        # additionally, communicate(), or poll() and wait process to terminate
        # communicate() accepts optional input as stdin to the pipe (requires setting stdin=subprocess.PIPE above), return out, err as tuple
        # if communicate(), the results are buffered in memory

        # Read stdout from subprocess until the buffer is empty !
        # if error occurs, the stdout is '', which means the below loop is essentially skipped
        # A prefix of 'b' or 'B' is ignored in Python 2; 
        # it indicates that the literal should become a bytes literal in Python 3 
        # (e.g. when code is automatically converted with 2to3).
        # return iter(p.stdout.readline, b'')
        for line in iter(p.stdout.readline, b''):
            # # Windows has \r\n, Unix has \n, Old mac has \r
            # if line not in ['','\n','\r','\r\n']: # Don't print blank lines
                yield line
        while p.poll() is None:                                                                                                                                        
            sleep(.1) #Don't waste CPU-cycles
        # Empty STDERR buffer
        err = p.stderr.read()
        if p.returncode != 0:
            # responsible for logging STDERR 
            print("Error: " + str(err))
            yield None

    out = []
    for line in _execute_cmd(cmd):
        # error did not occur earlier
        if line is not None:
            # trailing comma to avoid a newline (by print itself) being printed
            if output: print line,
            out.append(line.strip())
        else:
            # error occured earlier
            out = None
    return out
else:
    print "Simulation! The command is " + cmd
    print ""

0

ප්‍රතිදානය පෙළ ගොනුවකට හරවා යවා නැවත කියවිය හැකිය.

import subprocess
import os
import tempfile

def execute_to_file(command):
    """
    This function execute the command
    and pass its output to a tempfile then read it back
    It is usefull for process that deploy child process
    """
    temp_file = tempfile.NamedTemporaryFile(delete=False)
    temp_file.close()
    path = temp_file.name
    command = command + " > " + path
    proc = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
    if proc.stderr:
        # if command failed return
        os.unlink(path)
        return
    with open(path, 'r') as f:
        data = f.read()
    os.unlink(path)
    return data

if __name__ == "__main__":
    path = "Somepath"
    command = 'ecls.exe /files ' + path
    print(execute(command))

එය කළ හැකි බව විශ්වාසයි, නමුත් ඔබට අවශ්‍ය ඇයි? ඔබ පසුකර යනවා වෙනුවට කවචය භාවිතා කරන්නේ ඇයි stdout=temp_file?
ත්‍රිත්ව

ඇත්ත වශයෙන්ම, සාමාන්‍යයෙන් ඔබ නිවැරදියි නමුත් මගේ උදාහරණයේ දී ecls.exeවෙනත් විධාන රේඛා මෙවලමක් යෙදූ බව පෙනේ, එබැවින් සරල ක්‍රමය සමහර විට ක්‍රියාත්මක නොවීය.
මසූඩ් රහමි

0

curl භාවිතා කරමින් මෙය කිරීමට කුඩා බෑෂ් පිටපතක් ලිවීය

https://gist.github.com/harish2704/bfb8abece94893c53ce344548ead8ba5

#!/usr/bin/env bash

# Usage: gdrive_dl.sh <url>

urlBase='https://drive.google.com'
fCookie=tmpcookies

curl="curl -L -b $fCookie -c $fCookie"
confirm(){
    $curl "$1" | grep jfk-button-action | sed -e 's/.*jfk-button-action" href="\(\S*\)".*/\1/' -e 's/\&amp;/\&/g'
}

$curl -O -J "${urlBase}$(confirm $1)"

0

මෙන්න විසඳුමක්, ක්‍රියාවලිය ක්‍රියාත්මක වන විට හෝ නැති විට ප්‍රතිදානය මුද්‍රණය කිරීමට අවශ්‍ය නම් වැඩ කිරීම.


මම වත්මන් වැඩ නාමාවලියද එක් කළෙමි, එය මට කිහිප වතාවක්ම ප්‍රයෝජනවත් විය.


විසඳුම බලාපොරොත්තු වීම කෙනෙකුට උපකාරී වේ :).

import subprocess

def run_command(cmd_and_args, print_constantly=False, cwd=None):
"""Runs a system command.

:param cmd_and_args: the command to run with or without a Pipe (|).
:param print_constantly: If True then the output is logged in continuous until the command ended.
:param cwd: the current working directory (the directory from which you will like to execute the command)
:return: - a tuple containing the return code, the stdout and the stderr of the command
"""
output = []

process = subprocess.Popen(cmd_and_args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd)

while True:
    next_line = process.stdout.readline()
    if next_line:
        output.append(str(next_line))
        if print_constantly:
            print(next_line)
    elif not process.poll():
        break

error = process.communicate()[1]

return process.returncode, '\n'.join(output), error

පයිතන් 3 සහ 2.7 යන දෙවර්ගයේම වැඩ කිරීම
ප්‍රීතිය jedidja Ndjama
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.