簡體   English   中英

如何從python傳遞許多bash命令?

[英]How to pipe many bash commands from python?

嗨,我正在嘗試從python調用以下命令:

comm -3 <(awk '{print $1}' File1.txt | sort | uniq) <(awk '{print $1}' File2.txt | sort | uniq) | grep -v "#" | sed "s/\t//g"

當comm命令的輸入也通過管道傳輸時,如何進行調用?

有沒有簡單而直接的方法呢?

我嘗試了子流程模塊:

subprocess.call("comm -3 <(awk '{print $1}' File1.txt | sort | uniq) <(awk '{print $1}' File2.txt | sort | uniq) | grep -v '#' | sed 's/\t//g'")

沒有成功,它說:OSError:[Errno 2]沒有這樣的文件或目錄

還是我必須單獨創建不同的調用,然后使用PIPE傳遞它們,如子流程文檔中所述:

p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
output = p2.communicate()[0]

進程替換( <() )是僅bash的功能。 因此,您需要一個shell,但它不能僅僅是任何shell(例如/bin/sh ,在非Windows平台上被shell=True使用),它必須是bash

subprocess.call(['bash', '-c', "comm -3 <(awk '{print $1}' File1.txt | sort | uniq) <(awk '{print $1}' File2.txt | sort | uniq) | grep -v '#' | sed 's/\t//g'"])

順便說一句,如果你打算是想與任意文件名的這條路線,傳遞出來的帶外(如下圖所示:傳遞_$0File1.txt$1 ,和File2.txt$2 ):

subprocess.call(['bash', '-c',
  '''comm -3 <(awk '{print $1}' "$1" | sort | uniq) '''
  '''        <(awk '{print $1}' "$2" | sort | uniq) '''
  '''        | grep -v '#' | tr -d "\t"''',
  '_', "File1.txt", "File2.txt"])

也就是說,最佳實踐方法的確是您自己建立鏈。 下面是與Python 3.6測試(注意需要對pass_fds參數subprocess.Popen使簡稱通過文件描述符/dev/fd/##提供鏈接):

awk_filter='''! /#/ && !seen[$1]++ { print $1 }'''

p1 = subprocess.Popen(['awk', awk_filter],
                      stdin=open('File1.txt', 'r'),
                      stdout=subprocess.PIPE)
p2 = subprocess.Popen(['sort', '-u'],
                      stdin=p1.stdout,
                      stdout=subprocess.PIPE)
p3 = subprocess.Popen(['awk', awk_filter],
                      stdin=open('File2.txt', 'r'),
                      stdout=subprocess.PIPE)
p4 = subprocess.Popen(['sort', '-u'],
                      stdin=p3.stdout,
                      stdout=subprocess.PIPE)
p5 = subprocess.Popen(['comm', '-3',
                       ('/dev/fd/%d' % (p2.stdout.fileno(),)),
                       ('/dev/fd/%d' % (p4.stdout.fileno(),))],
                      pass_fds=(p2.stdout.fileno(), p4.stdout.fileno()),
                      stdout=subprocess.PIPE)
p6 = subprocess.Popen(['tr', '-d', '\t'],
                      stdin=p5.stdout,
                      stdout=subprocess.PIPE)
result = p6.communicate()

這是很多代碼,但是(假設文件名在現實世界中已被參數化),它也是更安全的代碼-您不容易受到像ShellShock這樣的由啟動shell的簡單動作觸發的bug的攻擊,並且不要無需擔心會帶外傳遞變量以避免注入攻擊(除非是腳本語言解釋程序本身的命令參數(如awk的上下文中)。


也就是說,要考慮的另一件事是僅在本機Python中實現整個事情。

lines_1 = set(line.split()[0] for line in open('File1.txt', 'r') if not '#' in line)
lines_2 = set(line.split()[0] for line in open('File2.txt', 'r') if not '#' in line)
not_common = (lines_1 - lines_2) | (lines_2 - lines_1)
for line in sorted(not_common):
  print line

還結帳鉛。 讓生活更輕松

http://plumbum.readthedocs.io/en/latest/

流水線

這可能是錯誤的,但是您可以嘗試以下操作:

from plumbum.cmd import grep, comm, awk, sort, uniq, sed 
_c1 = awk['{print $1}', 'File1.txt'] | sort | uniq
_c2 = awk['{print $1}', 'File2.txt'] | sort | uniq
chain = comm['-3', _c1(), _c2() ] | grep['-v', '#'] | sed['s/\t//g']
chain()

讓我知道這是否出錯,將嘗試修復它。

編輯:正如我指出的那樣,我錯過了替換的事情,我認為必須通過將以上命令輸出重定向到一個臨時文件,然后在comm參數中使用該文件來明確地完成替換。

因此,以上內容實際上變為:

from plumbum.cmd import grep, comm, awk, sort, uniq, sed 
_c1 = awk['{print $1}', 'File1.txt'] | sort | uniq
_c2 = awk['{print $1}', 'File2.txt'] | sort | uniq
(_c1 > "/tmp/File1.txt")(), (_c2 > "/tmp/File2.txt")()
chain = comm['-3', "/tmp/File1.txt", "/tmp/File2.txt" ] | grep['-v', '#'] | sed['s/\t//g']
chain()

另外,也可以通過使用mkfifo使用@charles描述的方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM