check_call()子进程出错,执行' mv' unix命令:"语法错误:'('意外"

时间:2015-02-11 12:28:42

标签: python bash shell sh travis-ci

我正在为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)

...

当特拉维斯大楼达到那条线时,我收到了一个错误:

/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... script: # Here is the previous Travis code - mv !(my_project|cmake-3.0.2-Darwin64-universal) ./my_project/final_folder ... 个文件夹1}}。如果我在Linux shell上执行此命令,我会得到我的目标,但不是通过check_call()命令。

注意:我无法逐个移动文件,因为还有很多其他文件

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

.travis.yml

{{1}}

有效。但如果我使用该脚本,则会失败。

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

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

3 个答案:

答案 0 :(得分:2)

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

当您使用/bin/sh时,python子进程模块明确使用shell=True默认情况下允许使用这样的bash功能(&#39) ;遵守法律使其更像原始sh)。

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

subprocess.check_call(["bash", "-O", "extglob", "-c", "mv !(my_project|cmake-3.0.2-Darwin64-universal) ./my_project/final_folder"])
但是,我不会选择以这种方式完成工作。

答案 1 :(得分:0)

让我再试一次:你期望在哪个shell中使用语法!(...)?是bash吗?是ksh吗?我从来没有使用它,快速搜索相应的bash功能无处可去。我怀疑你的语法只是错误,这是错误信息告诉你的。在这种情况下,您的问题完全独立于python和subprocess模块。

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

编辑:您引用的SO解决方案包含注释中的解决方案:

  

提示:请注意,使用此模式依赖于 extglob 。您可以   使用shopt -s extglob启用它(如果你想扩展globs   默认情况下你可以将shopt -s extglob添加到.bashrc)

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

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

然后,使用/ bin / dash:

$ !(uname)
Linux

答案 2 :(得分:-1)

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

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

编辑: 因此,目标是移动文件/目录,同时免除某些文件/目录(ies)。通过玩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),它应该按照您的预期进行。