以智能和干净的方式拆分bash命令参数
我的最终目标是以一种干净的方式迭代bash中最后一个命令行中使用的所有参数,以便找到目录的任何路径。 我希望的例子如下:以智能和干净的方式拆分bash命令参数,bash,shell,awk,scripting,split,Bash,Shell,Awk,Scripting,Split,我的最终目标是以一种干净的方式迭代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 myf
$ 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
}
/afac/soq $ cd ..
/afac $ myfunc
cd
..
/afac $ touch "some file.txt"
/afac $ myfunc
touch
some file.txt
#!/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
我喜欢以这种方式使用eval
的简单性,因为它可以处理自动引用的参数、转义空格、全局扩展等。。。所以我不必自己用复杂的awk
或sed
命令来处理这个问题
它适用于单个命令,如下所示:
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
}
/afac/soq $ cd ..
/afac $ myfunc
cd
..
/afac $ touch "some file.txt"
/afac $ myfunc
touch
some file.txt
#!/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
但是很明显(由于数组定义中的“;”),当我在一行中使用多个命令时,它会失败:
$ 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 '&&'
因此,要使其工作,我必须在时将命令字符串拆分为多个部分遇到code>、&&
或|
时,不会忘记转义或引用这些令牌的情况,然后告别简单性。。。我甚至不知道我是否能够以一种好的方式解析它,以我目前关于sed
和awk
的知识
将一个命令的所有参数放入一个数组,处理在一行上引用参数、转义字符和多个命令的可能性,最干净(也是最简单)的解决方案是什么
它可能非常重复,但我在任何地方都找不到任何真正的解决方案。您可以做得更好,尽管不是所有情况下都可以:
function myfunc(){
set -- $(history 2 | sed 's/[ 0-9]*//;1q')
for arg
do echo "$arg"
done
}
现在我只能生产这样的产品:
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
}
/afac/soq $ cd ..
/afac $ myfunc
cd
..
/afac $ touch "some file.txt"
/afac $ myfunc
touch
some file.txt
#!/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
#/bin/bash
last_cmd='echo 12“3 4”&&echo“A B”C | | echo D“E F”&'
#将任何:&、&&或| |转换为分号
cmd=$(sed-e's/&\?[]*&&//g'-e's/&\?[]*|//g'-e's/&[]*$/'那么,您的args
数组在以下命令中的预期内容是什么:echo'1 2 3'&&echo'A B'C
@Eugeniu Rosca:类似于(echo'1 2 3'&'echo'A B'C)或(echo'1 2 3'A B'C)
。重要的是每个有效参数都存在,这样我就可以在循环中使用类似于[-d${args[$I]}]]
的东西来测试它们,而不是eval“args=($last_com)”
,尝试IFS=''args=($last_com)
Tx提供帮助,但它确实没有帮助:它将带空格的带引号的字符串分割成小的无用块(这就是为什么我喜欢使用eval
,因为bash
然后在没有多个命令的情况下,自己完成所有解析工作)谢谢你,它让我通过bash
学到了一些东西,但是当引号中有空格时,它不会很巧妙地拆分单词;但是我必须再仔细看一看,它不是一个完美的解决方案,但如果没有更好的答案,它会在一段时间内将其设置为答案…谢谢你的帮助也许有人会用一种非常简单的方法来实现它h这是。不要将问题标记为已回答。因为您真正想要的是从命令历史记录中提取一些目录/文件路径,我认为您可以简单地从$last_cmd
中删除所有特殊字符,例如:[].*^.+&$!%
。检查更新版本。非常好的主意;我会稍微调整字符列表(特别是添加分号),但它做得相当好!