子进程命令未使用 ls 命令查找文件?
Subprocess command not finding files using ls command?
我正在创建一个程序,它将拉入一个帐号列表,然后 运行 一个 ls -lh
命令为每个帐号查找一个文件。当我在没有 Python 的 Linux 服务器上 运行 我的命令时,它没有问题地提取文件,但是当我通过 Python 执行它时,它说找不到他们。
import subprocess as sp
sp.call(['cd', input_dir])
for i, e in enumerate(piv_id_list):
proc_out = sp.Popen(['ls', '-lh', '*CSV*APP*{0}.zip'.format(e)])
proc_out_list.append(proc_out)
print(proc_out)
这是我通过 Python 解释器 运行 命令时的一些示例输出:
>>> ls: cannot access *CSV1000*APP*: No such file or directory
但是通过Linux相同的命令:
ls -lh *CSV*APP*
它 returns 应该的输出。
这是因为 shell 会用与模式匹配的现有文件替换通配符。例如,如果您有 a.txt
和 b.txt
,那么 ls *.txt
将从 shell 扩展为 ls a.txt b.txt
。使用您的命令,您实际上要求 ls
到 return 有关文件名中包含星号的文件的信息。如果要验证,请使用以下内容:
sp.Popen(['bash', '-c', 'ls', '-lh', '*CSV*APP*{0}.zip'.format(e)])
您还应该使用 os.chdir
更改目录,因为 sp.call(['cd', input_dir])
更改了您创建的新进程的当前目录,而不是父进程。
我认为您需要将 shell=True
作为参数添加到 Popen 并用一个字符串替换列表:
proc_out = sp.Popen('ls -lh *CSV*APP*{0}.zip'.format(e), shell=True)
有关 glob
的更多信息和可能用法,请参阅此处:Python subprocess wildcard usage
您应该使用 cwd
argument to Popen
and shell=True
, then communicate
来获取输出。
您的代码如下所示:
import subprocess as sp
for i, e in enumerate(piv_id_list):
proc = sp.Popen(['ls', '-lh', '*CSV*APP*{0}.zip'.format(e)], cwd=input_dir, stdout=sp.PIPE, shell=True)
proc_out_list.append(proc.communicate()[0])
print(proc_out_list[-1])
但是为什么要创建子进程而不是使用标准库?
编辑
如@tripleee所说,它只是替换了一些功能。
我认为尽可能使用 builtins/stdlib 更好;在您的情况下,您 "only" 想要列出给定模式 (glob
) and show ordered (sorted
) informations about their size (stat
) 的文件。
使用stdlib 使您的代码更具可移植性;即使您不关心 Microsoft Windows 可移植性,您也可能希望避免 运行 使您的代码在没有 GNU binutils 的计算机上 运行 意外(即:Mac OS, BSD, ...).
您想使用 subprocess
模块来处理无法(轻松)在纯 Python 中实现的事情(即:使用 ffmpeg
编码视频,使用 ffmpeg
更改用户密码passwd
,使用 sudo
,...升级权限。
ls
,从 运行 到 Python,可能是正确的:我猜 没有 文件叫 *CSV*APP*
在当前目录中。可能有一个名称与该 glob 模式匹配的文件。但是 ls
不关心 glob。当您 运行 shell 上的命令时,会发生什么 shell 将 glob 扩展为它在当前目录中可以看到的匹配文件名,这些扩展名就是 shell 传递给 ls
.
要在 shell 中获得与 Python 中相同的结果(为了演示,而不是因为你想要那样),请用单引号保护参数免受 glob 扩展:
ls -lh '*CVS*APP*'${e}'.zip'
但是如何在 Python 中获得 shell 的行为?您可以像其他一些答案所建议的那样使用 shell=True
,但这是一个滑坡,因为在动态生成的字符串上调用实际的 shell (可能取决于更复杂的应用程序中的用户输入)可以使您容易受到命令注入和其他恶意行为的影响。
在这里,您仅需要一个 shell、文件名通配的特定行为。而 Python 恰好能够做到这一点 all by itself:
import subprocess as sp
from glob import glob
sp.call(['cd', input_dir])
for i, e in enumerate(piv_id_list):
proc_out = sp.Popen(['ls', '-lh', glob('*CSV*APP*{0}.zip'.format(e))])
proc_out_list.append(proc_out)
print(proc_out)
As ,这仍然会在错误的目录中查找,因为 cd
只会影响 of the cd
调用,所以让我们也解决这个问题:
import subprocess as sp
from glob import glob
os.chdir(input_dir)
for i, e in enumerate(piv_id_list):
proc_out = sp.Popen(['ls', '-lh', glob('*CSV*APP*{0}.zip'.format(e))])
proc_out_list.append(proc_out)
print(proc_out)
笔记
您可以直接使用 slightly higher-level sp.check_output
instead of the underlying sp.Popen
。
我正在创建一个程序,它将拉入一个帐号列表,然后 运行 一个 ls -lh
命令为每个帐号查找一个文件。当我在没有 Python 的 Linux 服务器上 运行 我的命令时,它没有问题地提取文件,但是当我通过 Python 执行它时,它说找不到他们。
import subprocess as sp
sp.call(['cd', input_dir])
for i, e in enumerate(piv_id_list):
proc_out = sp.Popen(['ls', '-lh', '*CSV*APP*{0}.zip'.format(e)])
proc_out_list.append(proc_out)
print(proc_out)
这是我通过 Python 解释器 运行 命令时的一些示例输出:
>>> ls: cannot access *CSV1000*APP*: No such file or directory
但是通过Linux相同的命令:
ls -lh *CSV*APP*
它 returns 应该的输出。
这是因为 shell 会用与模式匹配的现有文件替换通配符。例如,如果您有 a.txt
和 b.txt
,那么 ls *.txt
将从 shell 扩展为 ls a.txt b.txt
。使用您的命令,您实际上要求 ls
到 return 有关文件名中包含星号的文件的信息。如果要验证,请使用以下内容:
sp.Popen(['bash', '-c', 'ls', '-lh', '*CSV*APP*{0}.zip'.format(e)])
您还应该使用 os.chdir
更改目录,因为 sp.call(['cd', input_dir])
更改了您创建的新进程的当前目录,而不是父进程。
我认为您需要将 shell=True
作为参数添加到 Popen 并用一个字符串替换列表:
proc_out = sp.Popen('ls -lh *CSV*APP*{0}.zip'.format(e), shell=True)
有关 glob
的更多信息和可能用法,请参阅此处:Python subprocess wildcard usage
您应该使用 cwd
argument to Popen
and shell=True
, then communicate
来获取输出。
您的代码如下所示:
import subprocess as sp
for i, e in enumerate(piv_id_list):
proc = sp.Popen(['ls', '-lh', '*CSV*APP*{0}.zip'.format(e)], cwd=input_dir, stdout=sp.PIPE, shell=True)
proc_out_list.append(proc.communicate()[0])
print(proc_out_list[-1])
但是为什么要创建子进程而不是使用标准库?
编辑
如@tripleee所说,它只是替换了一些功能。
我认为尽可能使用 builtins/stdlib 更好;在您的情况下,您 "only" 想要列出给定模式 (glob
) and show ordered (sorted
) informations about their size (stat
) 的文件。
使用stdlib 使您的代码更具可移植性;即使您不关心 Microsoft Windows 可移植性,您也可能希望避免 运行 使您的代码在没有 GNU binutils 的计算机上 运行 意外(即:Mac OS, BSD, ...).
您想使用 subprocess
模块来处理无法(轻松)在纯 Python 中实现的事情(即:使用 ffmpeg
编码视频,使用 ffmpeg
更改用户密码passwd
,使用 sudo
,...升级权限。
ls
,从 运行 到 Python,可能是正确的:我猜 没有 文件叫 *CSV*APP*
在当前目录中。可能有一个名称与该 glob 模式匹配的文件。但是 ls
不关心 glob。当您 运行 shell 上的命令时,会发生什么 shell 将 glob 扩展为它在当前目录中可以看到的匹配文件名,这些扩展名就是 shell 传递给 ls
.
要在 shell 中获得与 Python 中相同的结果(为了演示,而不是因为你想要那样),请用单引号保护参数免受 glob 扩展:
ls -lh '*CVS*APP*'${e}'.zip'
但是如何在 Python 中获得 shell 的行为?您可以像其他一些答案所建议的那样使用 shell=True
,但这是一个滑坡,因为在动态生成的字符串上调用实际的 shell (可能取决于更复杂的应用程序中的用户输入)可以使您容易受到命令注入和其他恶意行为的影响。
在这里,您仅需要一个 shell、文件名通配的特定行为。而 Python 恰好能够做到这一点 all by itself:
import subprocess as sp
from glob import glob
sp.call(['cd', input_dir])
for i, e in enumerate(piv_id_list):
proc_out = sp.Popen(['ls', '-lh', glob('*CSV*APP*{0}.zip'.format(e))])
proc_out_list.append(proc_out)
print(proc_out)
As cd
只会影响 of the cd
调用,所以让我们也解决这个问题:
import subprocess as sp
from glob import glob
os.chdir(input_dir)
for i, e in enumerate(piv_id_list):
proc_out = sp.Popen(['ls', '-lh', glob('*CSV*APP*{0}.zip'.format(e))])
proc_out_list.append(proc_out)
print(proc_out)
笔记
您可以直接使用 slightly higher-level sp.check_output
instead of the underlying sp.Popen
。