我正在为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大楼达到这条线时,我得到了一个错误:
/bin/sh: 1: Syntax error: "(" unexpected
我只是尝试了很多不同的形式来写它,但我得到了相同的结果。知道吗?
提前感谢!
编辑
我当前的目录布局:
- my_project/final_folder/
- cmake-3.0.2-Darwin64-universal/
- fileA
- fileB
- fileC
我正在尝试使用此命令将所有当前文件fileA
、fileB
和fileC
(不包括my_project
和cmake-3.0.2-Darwin64-universal
文件夹)移动到./my_project/final_folder
中。如果我在Linux shell上执行这个命令,我会得到目标,但不是通过check_call()命令。
注意:我无法逐个移动文件,因为还有很多其他
我不知道Travis默认使用的是哪个shell,因为我没有指定它,我只知道如果我在.Travis.yml:中编写命令
.travis.yml
...
script:
# Here is the previous Travis code
- mv !(my_project|cmake-3.0.2-Darwin64-universal) ./my_project/final_folder
...
它有效。但如果我使用脚本,它就会失败。
我从以下问题中找到了此命令:
如何使用"mv"命令移动特定目录中的文件以外的文件?
您正在使用bash功能extglob
,试图排除您指定的文件。您需要启用它才能使它排除您指定的两个条目。
当您使用shell=True
时,python子流程模块显式地使用/bin/sh
,默认情况下不会启用类似这样的bash功能(使其更像原始sh
是一件符合性的事情)。
如果您想让bash来解释该命令;您必须显式地将其传递给bash,例如使用:
subprocess.check_call(["bash", "-O", "extglob", "-c", "mv !(my_project|cmake-3.0.2-Darwin64-universal) ./my_project/final_folder"])
不过,我不会选择以这种方式来做这项工作。
让我再试一次:您希望语法!(...)
在哪个shell中工作?是狂欢吗?是ksh吗?我从未使用过它,快速搜索相应的bash功能也无济于事。我怀疑您的语法是错误的,这就是错误消息告诉您的。在这种情况下,您的问题完全独立于python和subprocess
模块。
如果系统上有一个特殊的shell支持这种语法,则需要确保Python在调用命令时使用相同的shell。它告诉您它一直在使用哪个shell:/bin/sh
。这通常只是指向真正的shell可执行文件的链接。它是否指向您在其中测试命令的同一个shell?
编辑:您引用的SO解决方案包含注释中的解决方案:
提示:但是请注意,使用此模式依赖于extglob。你可以使用shopt的extglob启用它(如果您希望扩展glob默认情况下打开后,您可以将shopt的extglob添加到.bashrc)
为了证明不同的shell可能以不同的方式处理您的语法,首先使用bash:
$ !(uname)
-bash: !: event not found
然后,使用/bin/dash:
$ !(uname)
Linux
subprocess.something
方法的参数必须是命令行参数列表。使用例如shlex.split()
将字符串拆分为正确的命令行参数:
import shlex, subprocess
subprocess.check_call( shlex.split("mv !(...)") )
编辑:因此,目标是移动文件/目录,但某些文件/目录除外。通过玩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)
,它应该做你期望它做的事情。