<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          用 Python 創(chuàng)建你自己的 Shell

          共 1138字,需瀏覽 3分鐘

           ·

          2021-02-05 08:58


          介紹
          很多人討厭bash腳本。每當(dāng)我要做最簡單的事情時(shí),我都必須查閱文檔。如何將函數(shù)的參數(shù)轉(zhuǎn)發(fā)給子命令?如何將字符串分配給變量,然后作為命令調(diào)用該字符串?如何檢查兩個(gè)字符串變量是否相等?如何分割字符串并獲得后半部分?等等。不是我找不到這些答案,而是每次都必須查找它們。
          但是,我們不能否認(rèn)將整個(gè)程序當(dāng)作純粹的功能發(fā)揮作用的能力,以及將一個(gè)程序的輸出傳遞到另一個(gè)程序的自然程度。因此,我想知道,我們能否將bash的某些功能與Python結(jié)合起來?
          基礎(chǔ)知識(shí)
          讓我們從一個(gè)類開始。這是一個(gè)簡單的方法,將其初始化參數(shù)保存到局部變量,然后使用subprocess.run對其自身進(jìn)行延遲求值并保存結(jié)果。
          import?subprocess

          class?PipePy:
          ????def?__init__(self,?*args):
          ????????self._args?=?args
          ????????self._result?=?None

          ????def?_evaluate(self):
          ????????if?self._result?is?not?None:
          ????????????return
          ????????self._result?=?subprocess.run(self._args,
          ??????????????????????????????????????capture_output=True,
          ??????????????????????????????????????text=True)

          ????@property
          ????def?returncode(self):
          ????????self._evaluate()
          ????????return?self._result.returncode

          ????@property
          ????def?stdout(self):
          ????????self._evaluate()
          ????????return?self._result.stdout

          ????def?__str__(self):
          ????????return?self.stdout

          ????@property
          ????def?stderr(self):
          ????????self._evaluate()
          ????????return?self._result.stderr
          我們讓它旋轉(zhuǎn)一下:
          ls?=?PipePy('ls')
          ls_l?=?PipePy('ls',?'-l')

          print(ls)
          #?<<
          #?...?main.py
          #?...?tags
          print(ls_l)
          #?<<
          #?...?-rw-r--r--?1?kbairak?kbairak??125?Jan?22?08:53?files.txt
          #?...?-rw-r--r--?1?kbairak?kbairak?5425?Feb??1?21:54?main.py
          #?...?-rw-r--r--?1?kbairak?kbairak?1838?Feb??1?21:54?tags
          使其看起來更像“命令式”
          不用每次我們要自定義命令時(shí)都去調(diào)用PipePy。
          ls_l?=?PipePy('ls',?'-l')
          print(ls_l)
          相當(dāng)于
          ls?=?PipePy('ls')
          print(ls('-l'))
          換句話說,我們要使:
          PipePy('ls',?'-l')
          相當(dāng)于
          PipePy('ls')('-l')
          值得慶幸的是,我們的類創(chuàng)建了惰性對象這一事實(shí)在很大程度上幫助了我們:
          class?PipePy:
          ????#?__init__,?etc

          ????def?__call__(self,?*args):
          ????????args?=?self._args?+?args
          ????????return?self.__class__(*args)

          ls?=?PipePy('ls')
          print(ls('-l'))
          #?<<
          #?...?-rw-r--r--?1?kbairak?kbairak??125?Jan?22?08:53?files.txt
          #?...?-rw-r--r--?1?kbairak?kbairak?5425?Feb??1?21:54?main.py
          #?...?-rw-r--r--?1?kbairak?kbairak?1838?Feb??1?21:54?tags
          關(guān)鍵字參數(shù)
          如果要向ls傳遞更多參數(shù),則可能會(huì)遇到--sort = size。我們可以輕松地執(zhí)行ls('-l','--sort = size')。我們可以做得更好嗎?
          ?class?PipePy:
          -????def?__init__(self,?*args):
          +????def?__init__(self,?*args,?**kwargs):
          ?????????self._args?=?args
          +????????self._kwargs?=?kwargs
          ?????????self._result?=?None

          ?????def?_evaluate(self):
          ?????????if?self._result?is?not?None:
          ?????????????return
          -????????self._result?=?subprocess.run(self._args,
          +????????self._result?=?subprocess.run(self._convert_args(),
          ???????????????????????????????????????capture_output=True,
          ???????????????????????????????????????text=True)
          ?
          +????def?_convert_args(self):
          +????????args?=?[str(arg)?for?arg?in?self._args]
          +????????for?key,?value?in?self._kwargs.items():
          +????????????key?=?key.replace('_',?'-')
          +????????????args.append(f"--{key}={value}")
          +????????return?args
          ?
          -????def?__call__(self,?*args):
          +????def?__call__(self,?*args,?**kwargs):
          ?????????args?=?self._args?+?args
          +????????kwargs?=?{**self._kwargs,?**kwargs}
          -????????return?self.__class__(*args)
          +????????return?self.__class__(*args,?**kwargs)

          ?????#?returncode,?etc
          讓我們來旋轉(zhuǎn)一下:
          print(ls('-l'))
          #?<<
          #?...?-rw-r--r--?1?kbairak?kbairak??125?Jan?22?08:53?files.txt
          #?...?-rw-r--r--?1?kbairak?kbairak?5425?Feb??1?21:54?main.py
          #?...?-rw-r--r--?1?kbairak?kbairak?1838?Feb??1?21:54?tags


          print(ls('-l',?sort="size"))
          #?<<
          #?...?-rw-r--r--?1?kbairak?kbairak?5425?Feb??1?21:54?main.py
          #?...?-rw-r--r--?1?kbairak?kbairak?1838?Feb??1?21:54?tags
          #?...?-rw-r--r--?1?kbairak?kbairak??125?Jan?22?08:53?files.txt
          Piping
          事情開始變得有趣起來。我們的最終目標(biāo)是能夠做到:
          ls?=?PipePy('ls')
          grep?=?PipePy('grep')

          print(ls?|?grep('tags'))
          #?<<
          我們的過程是:
          1、讓__init____call__方法接受一個(gè)僅用于關(guān)鍵字的新_pipe_input關(guān)鍵字參數(shù),該參數(shù)將保存在self上。
          2、在評估期間,如果設(shè)置了_pipe_input,它將作為輸入?yún)?shù)傳遞給subprocess.run
          3、重寫__or__方法以將左操作數(shù)的結(jié)果作為pipe輸入傳遞給右操作數(shù)。
          ?class?PipePy:
          -????def?__init__(self,?*args,?**kwargs):
          +????def?__init__(self,?*args,?_pipe_input=None,?**kwargs):
          ?????????self._args?=?args
          ?????????self._kwargs?=?kwargs
          +????????self._pipe_input?=?_pipe_input
          ?????????self._result?=?None
          ?
          -????def?__call__(self,?*args,?**kwargs):
          +????def?__call__(self,?*args,?_pipe_input=None,?**kwargs):
          ?????????args?=?self._args?+?args
          ?????????kwargs?=?{**self._kwargs,?**kwargs}
          -????????return?self.__class__(*args,?**kwargs)
          +????????return?self.__class__(*args,?_pipe_input=_pipe_input,?**kwargs)
          ?
          ?????def?_evaluate(self):
          ?????????if?self._result?is?not?None:
          ?????????????return
          ?????????self._result?=?subprocess.run(self._convert_args(),
          +??????????????????????????????????????input=self._pipe_input,
          ???????????????????????????????????????capture_output=True,
          ???????????????????????????????????????text=True)
          ?
          +????def?__or__(left,?right):
          +????????return?right(_pipe_input=left.stdout)
          讓我們嘗試一下(從之前稍微修改命令以證明它確實(shí)有效):
          ls?=?PipePy('ls')
          grep?=?PipePy('grep')

          print(ls('-l')?|?grep('tags'))
          #?<<
          讓我們添加一些簡單的東西
          1、真實(shí)性:
          class?PipePy:
          ????#?__init__,?etc

          ????def?__bool__(self):
          ????????return?self.returncode?==?0
          現(xiàn)在我們可以作出如下處理:
          git?=?PipePy('git')
          grep?=?PipePy('grep')

          if?git('branch')?|?grep('my_feature'):
          ????print("Branch?'my_feature'?found")
          2、讀取/寫入文件:
          class?PipePy:
          ????#?__init__,?etc

          ????def?__gt__(self,?filename):
          ????????with?open(filename,?'w')?as?f:
          ????????????f.write(self.stdout)

          ????def?__rshift__(self,?filename):
          ????????with?open(filename,?'a')?as?f:
          ????????????f.write(self.stdout)

          ????def?__lt__(self,?filename):
          ????????with?open(filename)?as?f:
          ????????????return?self(_pipe_input=f.read())
          現(xiàn)在可以作出如下操作:
          ls?=?PipePy('ls')
          grep?=?PipePy('grep')
          cat?=?PipePy('cat')

          ls?>?'files.txt'

          print(grep('main')?'files.txt')
          #?<<

          ls?>>?'files.txt'
          print(cat('files.txt'))
          #?<<
          #?...?main.py
          #?...?tags
          #?...?files.txt
          #?...?main.py
          #?...?tags
          3、迭代
          class?PipePy:
          ????#?__init__,?etc

          ????def?__iter__(self):
          ????????return?iter(self.stdout.split())
          現(xiàn)在可以作出如下操作:
          ls?=?PipePy('ls')

          for?name?in?ls:
          ????print(name.upper())
          #?<<
          #?...?MAIN.PY
          #?...?TAGS
          4、表格:
          class?PipePy:
          ????#?__init__,?etc

          ????def?as_table(self):
          ????????lines?=?self.stdout.splitlines()
          ????????fields?=?lines[0].split()
          ????????result?=?[]
          ????????for?line?in?lines[1:]:
          ????????????item?=?{}
          ????????????for?i,?value?in?enumerate(line.split(maxsplit=len(fields)?-?1)):
          ????????????????item[fields[i]]?=?value
          ????????????result.append(item)
          ????????return?result
          現(xiàn)在可以作出下面操作:
          ps?=?PipePy('ps')
          print(ps)
          #?<<
          #?...????4205?pts/4????00:00:00?zsh
          #?...???13592?pts/4????00:00:22?ptipython
          #?...???16253?pts/4????00:00:00?ps
          ps.as_table()
          #?<<
          #?...??{'PID':?'13592',?'TTY':?'pts/4',?'TIME':?'00:00:22',?'CMD':?'ptipython'},
          #?...??{'PID':?'16208',?'TTY':?'pts/4',?'TIME':?'00:00:00',?'CMD':?'ps'}]
          5、普通bash實(shí)用程序:
          在子進(jìn)程中更改工作目錄不會(huì)影響當(dāng)前的腳本或python shell。與更改環(huán)境變量相同,以下內(nèi)容不是PipePy的補(bǔ)充,但很不錯(cuò):
          import?os
          cd?=?os.chdir
          export?=?os.environ.__setitem__

          pwd?=?PipePy('pwd')

          pwd
          #?<<

          cd('..')
          pwd
          #?<<
          使事情看起來更shell-like
          如果我在交互式shell中,則希望能夠簡單地鍵入ls并完成它。
          class?PipePy:
          ????#?__init__,?etc

          ????def?__repr__(self):
          ????????return?self.stdout?+?self.stderr
          交互式shell
          >>>?ls?=?PipePy('ls')
          >>>?ls
          files.txt
          main.py
          tags
          我們的實(shí)例是惰性的,這意味著如果我們對它們的結(jié)果感興趣,則將對它們進(jìn)行評估,此后不再進(jìn)行評估。如果我們只是想確保已執(zhí)行該操作怎么辦?例如,假設(shè)我們有以下腳本:
          from?pipepy?import?PipePy
          tar?=?PipePy('tar')
          tar('-xf',?'some_archive.tar')
          print("File?extracted")
          該腳本實(shí)際上不會(huì)執(zhí)行任何操作,因?yàn)?/span>tar調(diào)用實(shí)際上并未得到評估。我認(rèn)為一個(gè)不錯(cuò)的慣例是,如果不帶參數(shù)調(diào)用__call__強(qiáng)制求值:
          ?class?PipePy:
          ?????def?__call__(self,?*args,?_pipe_input=None,?**kwargs):
          ?????????args?=?self._args?+?args
          ?????????kwargs?=?{**self._kwargs,?**kwargs}
          -????????return?self.__class__(*args,?_pipe_input=_pipe_input,?**kwargs)
          +????????result?=?self.__class__(*args,?_pipe_input=_pipe_input,?**kwargs)
          +????????if?not?args?and?not?_pipe_input?and?not?kwargs:
          +????????????result._evaluate()
          +????????return?result
          因此在編寫腳本時(shí),如果要確保實(shí)際上已調(diào)用命令,則必須用一對括號(hào)來調(diào)用它:
          ?from?pipepy?import?PipePy
          ?tar?=?PipePy('tar')
          -tar('-xf',?'some_archive.tar')
          +tar('-xf',?'some_archive.tar')()
          ?print("File?extracted")
          但是,我們還沒有解決問題??紤]一下:
          date?=?PipePy('date')
          date
          #?<<

          #?Wait?5?seconds

          date
          #?<<
          不好!date沒有改變。date對象將其_result保留在內(nèi)存中。隨后的評估實(shí)際上不會(huì)調(diào)用該命令,而只是返回存儲(chǔ)的值。
          一種解決方案是通過使用空括號(hào)來強(qiáng)制創(chuàng)建副本:
          date?=?PipePy('date')
          date()
          #?<<

          #?Wait?5?seconds

          date()
          #?<<
          另一個(gè)解決方案是:由PipePy構(gòu)造函數(shù)返回的實(shí)例不應(yīng)該是惰性的,但由__call__調(diào)用返回的實(shí)例將是惰性的。
          ?class?PipePy:
          -????def?__init__(self,?*args,?_pipe_input=None,?**kwargs):
          +????def?__init__(self,?*args,?_pipe_input=None,?_lazy=False,?**kwargs):
          ?????????self._args?=?args
          ?????????self._kwargs?=?kwargs
          ?????????self._pipe_input?=?_pipe_input
          +????????self._lazy?=?_lazy
          ?????????self._result?=?None
          ?
          ?????def?__call__(self,?*args,?_pipe_input=None,?**kwargs):
          ?????????args?=?self._args?+?args
          ?????????kwargs?=?{**self._kwargs,?**kwargs}
          -????????result?=?self.__class__(*args,?_pipe_input=_pipe_input,?**kwargs)
          +????????result?=?self.__class__(*args,
          +????????????????????????????????_pipe_input=_pipe_input,
          +????????????????????????????????_lazy=True,
          +????????????????????????????????**kwargs)
          ?????????if?not?args?and?not?_pipe_input?and?not?kwargs:
          ?????????????result._evaluate()
          ?????????return?result
          ?
          ?????def?_evaluate(self):
          -????????if?self._result?is?not?None:
          +????????if?self._result?is?not?None?and?self._lazy:
          ?????????????return
          ?????????self._result?=?subprocess.run(self._convert_args(),
          ???????????????????????????????????????input=self._pipe_input,
          ???????????????????????????????????????capture_output=True,
          ???????????????????????????????????????text=True)
          旋轉(zhuǎn)一下:
          date?=?PipePy('date')
          date
          #?<<

          #?Wait?5?seconds

          date
          #?<<
          并且可以預(yù)見的是,使用空調(diào)用的返回值將具有之前的行為:
          date?=?PipePy('date')
          d?=?date()
          d
          #?<<

          #?Wait?5?seconds

          d
          #?<<
          沒關(guān)系 您不會(huì)期望d會(huì)更新其值。
          越來越危險(xiǎn)
          好吧,ls('-l')不錯(cuò),但是如果我們像人類一樣簡單地做ls -l,那就太好了。嗯,我有個(gè)主意:
          class?PipePy:
          ????#?__init__,?etc

          ????def?__sub__(left,?right):
          ????????return?left(f"-{right}")
          現(xiàn)在可以作如下操作:
          ls?=?PipePy('ls')
          ls?-?'l'
          #?<<
          #?...?-rw-r--r--?1?kbairak?kbairak???46?Feb??1?23:04?files.txt
          #?...?-rw-r--r--?1?kbairak?kbairak?5425?Feb??1?21:54?main.py
          #?...?-rw-r--r--?1?kbairak?kbairak?1838?Feb??1?21:54?tags
          我們還有一步:
          l?=?'l'
          ls?-l
          現(xiàn)在無濟(jì)于事:
          import?string
          for?char?in?string.ascii_letters:
          ????if?char?in?locals():
          ????????continue
          ????locals()[char]?=?char

          class?PipePy:
          ????#?__init__,?etc
          更危險(xiǎn)的事情
          locals()給了我一個(gè)靈感。為什么我們必須一直實(shí)例化PipePy?我們無法在路徑中找到所有可執(zhí)行文件,并根據(jù)它們創(chuàng)建PipePy實(shí)例嗎?我們當(dāng)然可以!
          import?os
          import?stat

          for?path?in?os.get_exec_path():
          ????try:
          ????????names?=?os.listdir(path)
          ????except?FileNotFoundError:
          ????????continue
          ????for?name?in?names:
          ????????if?name?in?locals():
          ????????????continue
          ????????if?'x'?in?stat.filemode(os.lstat(os.path.join(path,?name)).st_mode):
          ????????????locals()[name]?=?PipePy(name)
          因此,現(xiàn)在,將我們擁有的所有內(nèi)容都放在一個(gè)python文件中,并刪除腳本(這是實(shí)際bash腳本的轉(zhuǎn)錄):
          from?pipepy?import?mysqladmin,?sleep,?drush,?grep

          for?i?in?range(10):
          ????if?mysqladmin('ping',
          ??????????????????host="mysql_drupal7",
          ??????????????????user="user",
          ??????????????????password="password"):
          ????????break
          ????sleep(1)()??#?Remember?to?actually?invoke

          if?not?drush('status',?'bootstrap')?|?grep('-q',?'Successful'):
          ????drush('-y',?'site-install',?'standard',
          ??????????db_url="mysql://user:password@mysql_drupal7:3306/drupal",
          ??????????acount_pass="kbairak")()??#?Remember?to?actually?invoke

          drush('en',?'tmgmt_ui',?'tmgmt_entity_ui',?'tmgmt_node_ui')()


          更多閱讀



          2020 年最佳流行 Python 庫 Top 10


          2020 Python中文社區(qū)熱門文章 Top 10


          5分鐘快速掌握 Python 定時(shí)任務(wù)框架

          特別推薦




          點(diǎn)擊下方閱讀原文加入社區(qū)會(huì)員

          瀏覽 66
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美在线a视频 | 国产亚洲精品久久久久动 | 欧美性爱五月天 | 国产ts在线 | 黑人大屌轮奸视频播放免费成人 |