Error in check_call() subprocess, executing 'mv' unix command: "Syntax error: '(' unexpected"

Error in check_call() subprocess, executing 'mv' unix command: "Syntax error: '(' unexpected"

我正在为 Travis CI 制作 python 脚本。

.travis.yml

...

script:
  - support/travis-build.py

...

python 文件 travis-build.py 是这样的:

#!/usr/bin/env python
from subprocess import check_call

...

check_call(r"mv !(my_project|cmake-3.0.2-Darwin64-universal) ./my_project/final_folder", shell=True)

...

当 Travis building 达到那条线时,我收到一个错误:

/bin/sh: 1: Syntax error: "(" unexpected

我只是尝试了很多不同的形式来写它,但我得到了相同的结果。有什么想法吗?

提前致谢!

编辑

我当前的目录布局:

- my_project/final_folder/
- cmake-3.0.2-Darwin64-universal/
- fileA
- fileB
- fileC

我正在尝试使用此命令移动所有当前文件 fileAfileBfileC,不包括 my_projectcmake-3.0.2-Darwin64-universal 文件夹./my_project/final_folder。如果我在 Linux shell 上执行此命令,我会瞄准但不是通过 check_call() 命令。

注意:我不能一个一个的移动文件,因为还有很多

我不知道 Travis 默认使用哪个 shell 因为我没有指定它,我只知道如果我在我的 .travis.yml:[=23 中写命令=]

.travis.yml

...

script:
  # Here is the previous Travis code
  - mv !(my_project|cmake-3.0.2-Darwin64-universal) ./my_project/final_folder

...

有效。但是如果我使用脚本,它会失败。

我从以下问题中找到了这个命令:

How to use 'mv' command to move files except those in a specific directory?

subprocess.something 方法的参数必须是命令行参数列表。使用例如shlex.split() 将字符串拆分为正确的命令行参数:

import shlex, subprocess
subprocess.check_call( shlex.split("mv !(...)") )

编辑: 因此,目标是移动 files/directories,但某些文件/目录除外。通过玩弄 bash,我可以让它像这样工作:

mv `ls | grep -v -e '\(exclusion1\|exclusion2\)'` my_project

所以在你的情况下是:

mv `ls | grep -v -e '\(myproject\|cmake-3.0.2-Darwin64-universal\)'` my_project

这可以进入 subprocess.check_call(..., shell=True) 并且它应该按照您的预期进行。

让我再试一次:shell 您希望您的语法 !(...) 能在其中工作吗?是bash吗?是ksh吗?我从未使用过它,快速搜索相应的 bash 功能也无济于事。我怀疑您的语法只是 错误 ,这就是错误消息告诉您的内容。在那种情况下,您的问题完全独立于 python 和 subprocess 模块。

如果您的系统上有一个特殊的 shell 支持此语法,您需要确保 Python 在调用您的命令时使用相同的 shell。它会告诉您它一直在使用哪个 shell:/bin/sh。这通常只是 link 到真正的 shell 可执行文件。它是否指向您在其中测试命令的 shell?

编辑:您引用的SO解决方案包含评论中的解决方案:

Tip: Note however that using this pattern relies on extglob. You can enable it using shopt -s extglob (If you want extended globs to be turned on by default you can add shopt -s extglob to .bashrc)

只是为了证明不同的 shell 可能会以不同的方式处理您的语法,首先使用 bash:

$ !(uname)
-bash: !: event not found

然后,使用 /bin/dash:

$ !(uname)
Linux

您正在使用 bash 功能 extglob 来尝试排除您指定的文件。您需要启用它才能排除您指定的两个条目。

python 子进程模块在您使用 shell=True 时显式使用 /bin/sh 不会 启用 [=28] =] 默认情况下这样的功能(使它更像原始 sh 是合规性的事情)。

如果你想得到bash解释命令;您必须明确地将其传递给 bash,例如使用:

subprocess.check_call(["bash", "-O", "extglob", "-c", "mv !(my_project|cmake-3.0.2-Darwin64-universal) ./my_project/final_folder"])

不过,我不会选择以这种方式完成工作。