【问题标题】:Command Substitution working on command line but not in script命令替换在命令行上工作但不在脚本中
【发布时间】:2015-09-08 08:04:41
【问题描述】:

使用 ubuntu 10.10 我在命令行上运行以下内容:

result="$(ls -d !(*.*))"
chmod +x $result

这会得到一个没有扩展名的文件列表,并使它们可执行。

但是当我将它移动到脚本文件(shell)时它不起作用。根据我在论坛上阅读的内容,这与在不同的子 shell 中运行的命令替换有关。

但我还没有找到适用于我的脚本的解决方案:(

那么如何获取命令的结果并将其存储在脚本中的变量中呢?

【问题讨论】:

  • 您可能在交互式外壳上启用了extglob,但在脚本中没有。尝试在脚本中的命令前添加shopt -s extglob
  • @user000001 是的,你是对的 :) ...好的,我现在必须去研究 extglob 和 shopt 的作用。如果您想将其粘贴到答案中,我会适当地标记它。谢谢
  • 我试过这样:bash -c 'shopt -s extglob; ls -d !(*.*)' 但没有成功。
  • 哇。 bash -c $'shopt -s extglob\nls -d !(*.*)' 有效。这真是太奇怪了。好像是先把这行完全解析,然后逐个执行。
  • @Alfe haha​​,这是一段不错的代码,对我来说,两行代码更容易阅读:o ... 否则我的大脑会受伤!

标签: linux bash ubuntu ubuntu-10.10


【解决方案1】:

(由于@user000001 似乎没有将他们的评论写到答案中,我会辛苦地写下答案。所以应该归功于他们。)

您正在使用的功能是bashextglob(扩展通配)功能。这是默认为交互式 shell 启用的,默认为非交互式 shell(即 shell 脚本)禁用。要启用它,请使用命令shopt -s extglob

请注意,此命令仅对 下面的行有效:

shopt -s extglob
ls -d !(*.*)

不影响解析同一行:

shopt -s extglob; ls -d !(*.*)   # won't work!!

总的来说,我想警告使用bash 的这些特殊功能。它使代码相当不可移植。我建议使用 POSIX 功能和工具,它们可以相当轻松地将代码移植到另一个平台,它们还代表了更多开发人员无需先查阅文档即可理解的某些可能性子集。

您想要实现的目标也可以使用find 来完成。这还具有与奇怪的文件名(例如包含空格、引号等)结合使用时不会出现问题的优点:

find . -maxdepth 1 -type f -name '*.*' -o -exec chmod +x "{}" \;

【讨论】: