bash脚本:构建命令然后执行

时间:2015-09-25 17:08:23

标签: bash shell

我正在尝试创建一个基本上接受f hello there my friend之类的参数的函数,并使用find搜索目录,以查找任何字符串的所有出现,因此它将是find | grep 'hello\|there\|my\|friend' 。我是shell脚本的新手,但我的代码如下:

function f { 
  cmd="find | grep '"
  for var in "$@"
  do 
    cmd="$cmd$var\\|"
  done
  cmd="${cmd%\\|}'"
  echo "$cmd"
  $cmd 
}

当我执行命令时,我得到了这个:

# f hello there my friend
find | grep 'hello\|there\|my\|friend'
find: `|': No such file or directory
find: `grep': No such file or directory
find: `\'hello\\|there\\|my\\|friend\'': No such file or directory

为什么它不起作用,我怎样才能使它工作?我想这与字符串没有转换为命令有关,但我不太了解shell脚本如何解决它。

4 个答案:

答案 0 :(得分:3)

不要将整个命令放在字符串中;只需构建grep

的参数
f () { 
  local grep_arg=''
  delim=''
  for var in "$@"; do
      grep_arg+="$delim$var"
      delim='\|'
  done
  echo "find | grep '$grep_arg'"
  find | grep "$grep_arg"
}

答案 1 :(得分:2)

要从bash中的脚本运行命令并捕获结果,请使用以下语法:

CMD_STRING="ls"
RESULT=$($CMD_STRING)
echo $RESULT

或者,只需运行命令:

CMD_STRING="ls"
eval $CMD_STRING

答案 2 :(得分:2)

您可以使用find的全部功能,而不是将grep的输出通过find。您需要构建一个包含以下选项的数组

-false -o -name '*string1*' ... -o -name '*stringn*'

传递给find(其中string1 ... stringn是作为参数传递的字符串):

f() {
   local i args=( -false )
   for i; do
      args+=( -o -name "*$i*" )
   done
   find "${args[@]}"
}

我们使用-false作为初始化程序,因此构建选项数组很简单;这也有好处(或缺点,取决于你的观点),如果没有给出选项,那么find会提前退出,而不会递归地列出目录的所有内容。

使用grep,您可以使用正则表达式来获得更强大的匹配功能;这里我们使用find的{​​{1}}选项,因此我们只能使用基本的整数:-name*?。如果您的[...]支持find选项(GNU -regex确实如此),并且确实需要正则表达式,则修改上一个函数很简单。

另一种可能性是使用Bash的扩展球:

find

这里需要注意的一些事项:

  • 整个功能都包含在子shell中 - 它不是拼写错误。这是为了简化一些事情:不需要使用局部变量,也不需要保存shell选项以在函数结束时恢复它们。
  • 第一行使用 evil f() ( IFS='|' eval 'glob="$*"' shopt -s globstar extglob nullglob IFS= printf '%s\n' **/*@($glob)* ) ,但是以一种安全的方式:它实际上是一种惯用的方法,用eval的第一个字符连接位置参数的元素(这里是管道人物)。
  • 我们需要将IFS设置为空字符串,以避免在glob IFS中进行单词拆分。
  • 全球**/*@($glob)*使用**/*@($glob)*globstar extglob(没有引号,不是拼写错误)。请参阅参考手册中的Pattern Matching

这个函数使用Bash的扩展globs,它与正则表达式不同(并且没有那么强大)(但对于大多数情况来说这应该足够了)。

答案 3 :(得分:0)

最通用的方式:您可以使用“ |”之类的符号(管道)和其他变量输入并从stdout获取结果。

function runcmd(){
  eval "$1"
}

result=$(runcmd "Any command ${here}")