我的最终目标是以干净的方式遍历bash中最后一个命令行中使用的所有参数,以便找到目录的任何路径。 我想要的例子:
$ cp some_file.txt /some/existing/folder; touch a_new_file.txt
$ my_find_func
Found "/some/existing/folder" in the last command.
我的问题是以正确的方式拆分最后一个命令,以便处理所有可能的情况。现在我正在使用这样的东西:
function myfunc()
{
last_com="$(history|tail -n2|head -n1|sed -n 's/^\s*[0-9]*\s*//p')"
eval "args=( $last_com )"
# Note: I don't care about the security issue that eval can cause
for arg in "${args[@]}"; do
echo "$arg"
done
}
我喜欢以这种方式使用eval
的简单,因为它处理自动引用的参数,转义空格,全局扩展等...所以我不必使用复杂的awk
或sed
命令自行处理。
单个命令可以正常工作,如下所示:
/afac/soq $ cd ..
/afac $ myfunc
cd
..
/afac $ touch "some file.txt"
/afac $ myfunc
touch
some file.txt
但显然(因为数组定义中的&#39 ;;'),当我在一行中使用多个命令时,它会失败:
$ touch a_file; rm a_file
$ myfunc
bash: syntax error near unexpected token ';'
$ touch a_file && rm a_file
$ myfunc
bash: syntax error near unexpected token '&&'
为了使其工作,我将不得不在遇到;
,&&
或||
时将命令字符串拆分为多个部分,而不会忘记这些令牌被转义的情况或引用,然后告别简单 ...我甚至不知道我是否能够以一种好的方式解析这个问题,并且掌握了我目前的知识{ {1}}和sed
...
将一个命令的所有参数放入一个数组,处理引用参数,转义字符,和多个命令的可能性是最干净(最简单)的解决方案是什么?线?
它可能完全重复,但我在任何地方都找不到任何真正的解决方案。
答案 0 :(得分:1)
现在我只能生产这样的东西:
#!/bin/bash
last_cmd='echo 1 2 "3 4" & && echo "A B" C || echo D "E F" & '
# Convert any of: &, && or || to semicolon
cmd=$(sed -e 's/&\?[ ]*&&/;/g' -e 's/&\?[ ]*||/;/g' -e 's/&[ ]*$//' <<< "$last_cmd")
# TODO: get rid of/convert any other symbols creating issues to eval
echo "processed cmd: $cmd"
# split the command string using semicolon as delimiter
IFS=';'
cmd_arr=($cmd)
IFS=' '
args=()
for onecmd in "${cmd_arr[@]}"; do
eval "args+=($onecmd)"
done
for arg in "${args[@]}"; do
echo "$arg"
done
第2版
last_cmd='echo 1 2 "3 4" && echo "A B" C || echo D ["E F"] $!%#^* '
# Remove ALL special characters not having a chance to appear in a pathname
cmd=$(sed 's/[][|*^#+&$!%]//g' <<< "$last_cmd")
echo "processed cmd: $cmd"
IFS=' ' eval "args=($cmd)"
for arg in "${args[@]}"; do
echo "$arg"
done
答案 1 :(得分:0)
你可以做得更好,但并非所有情况都可以:
function myfunc(){
set -- $(history 2 | sed 's/[ 0-9]*//;1q')
for arg
do echo "$arg"
done
}