将长 html 字符串作为参数传递给 bash 脚本(文件名太长)

将长 html 字符串作为参数传递给 bash 脚本(文件名太长)

我将 html 字符串作为输入传递给 bash 脚本:

脚本.py


def bash(commandStr):
    subprocess.Popen(commandStr, shell=True, executable="/bin/bash")
  
def sendmail(subject, to, body):
    bash(f"./email.sh '{to}' '{subject}' '{body}'")

电子邮件.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 脚本?

答案1

TL,DR:不要使用 bash,你不需要它。

有两个问题。你最大的一个是对论点的引用。另一种可能是命令行长度限制。

主要问题

TL、博士:

  1. 当您不需要 shell 时,不要调用 shell。
  2. 更一般地说,避免陷入需要多次解析某些内容的情况。通常很难做到正确。

你正在运行一个 bash 命令,比如

./email.sh '[email protected]' 'Something happened' '<html>
<body>
You are heading for trouble.
</body>
</html>'

Bash 解析该命令并./email.sh使用三个参数执行该程序。该程序./email.sh碰巧运行了 bash 的另一个实例,但这只是一个巧合:您不必为这两个目的使用相同的 shell。

但是,如果您将 HTML 中的文本更改为包含单引号怎么办?

./email.sh '[email protected]' '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,您可能会遇到各种不同的错误。您最终可能会在计算机上运行任意命令,这些命令可能是由可以在电子邮件中注入某些内容的恶意者指定的命令。您的代码是一个巨大的安全漏洞!

xkcd 327

一个简短的解决方案

中间的重击是没有用的。它根本没有帮助你,而且还增加了一个巨大的错误。

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'))

相关内容