將長 html 字元串作為參數傳遞給 bash 腳本(文件名太長)
我將一個 html 字元串作為輸入傳遞給 bash 腳本:
Script.py
def bash(commandStr): subprocess.Popen(commandStr, shell=True, executable="/bin/bash") def sendmail(subject, to, body): bash(f"./email.sh '{to}' '{subject}' '{body}'")
email.sh
#!/bin/bash # args: 1 - TO address # 2 - subject # 3 - body ( echo "To: $1"; echo "Subject: $2"; echo "Content-Type: text/html"; echo "MIME-Version: 1.0"; echo ""; echo "$3"; ) | sendmail -t
這成功地只發送了 html 的一個子集,然後我得到了錯誤:
File name too long
。我想提供一個完整的 HTML 字元串作為我的 bash 腳本的參數。我是 bash 腳本的新手,所以可能有一種我不知道的更好的方法來解決這個問題。我的一個限制是我確實需要從 python 呼叫 bash 腳本。如何將長 HTML 字元串作為參數傳遞給 bash 腳本?
TL,DR:不要使用 bash,你不需要它。
有兩個問題。你最大的一個是引用的論點。另一個可能是命令行長度限制。
主要問題
長話短說:
- 當您不需要 shell 時,不要呼叫 shell。
- 更一般地說,避免陷入需要多次解析的情況。通常很難做到正確。
您正在執行 bash 命令,例如
./email.sh 'bob@example.com' 'Something happened' '<html> <body> You are heading for trouble. </body> </html>'
./email.sh
Bash 解析這個命令並使用三個參數執行程序。該程序./email.sh
碰巧執行了另一個 bash 實例,但這只是巧合:您不必為這兩個目的使用相同的 shell。但是,如果您將 HTML 中的文本更改為包含單引號會怎樣?
./email.sh 'bob@example.com' 'Something happened' '<html> <body> You're heading for trouble. </body> </html>'
現在傳遞給的第三個參數
./email.sh
以Youre
. 有第四個參數heading
,第五個參數for
和第六個參數trouble.
然後,一旦./email.sh
返回,bash 解析並嘗試執行命令</body>
,導致錯誤bash: -c: line 4: syntax error near unexpected token `newline' bash: -c: line 4: `</body>'
使用一些稍微不同的 HTML,您可能會遇到各種不同的錯誤。你最終可能會在你的機器上執行任意命令,也許是惡意的人指定的命令,他們可以向電子郵件中註入一些內容。您的程式碼是一個巨大的安全漏洞!
一個簡短的解決方案
那個中間 bash 是沒用的。它根本沒有幫助你,並增加了一個巨大的錯誤。
def sendmail(subject, to, body): subprocess.Popen(["./email.sh", to, subject, body])
這更簡單,並且確實有效。
更強大的解決方案
如果電子郵件正文太長,您可能會遇到命令行長度(命令名、參數、環境變數)的限制。限制是 顯示的字節數
getconf ARG_MAX
。為避免這種情況,您可以將電子郵件正文作為輸入而不是作為命令行參數傳遞。
def sendmail(subject, to, body): subprocess.Popen(["./email.sh", to, subject], input=body.encode('utf-8'))
utf-8
(如果需要,用正確的字元集替換。)#!/bin/bash # args: 1 - TO address # 2 - subject # stdin: body ( echo "To: $1"; echo "Subject: $2"; echo "Content-Type: text/html"; echo "MIME-Version: 1.0"; echo ""; cat ) | sendmail -t
為什麼要使用 bash?
如果該電子郵件發送腳本正是您所展示的,那麼使用 bash 是沒有意義的。你可以在 Python 中完成這一切。
def sendmail(subject, to, body): mail = f"""\ To: f{to} Subject: f{subject} Content-Type: text/html MIME-Version: 1.0 f{body}""" subprocess.Popen(["sendmail", "-t"], input=mail.encode('utf-8'))