我正在尝试创建一个基本上接受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脚本如何解决它。
答案 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
这里需要注意的一些事项:
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}")