以智能和干净的方式拆分 bash 命令参数
Split bash command parameters in a smart and clean way
我的最终目标是以干净的方式遍历 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
的 简单性 ,因为它可以处理自动引用的参数、转义空格、glob 扩展等...所以我不不必自己用复杂的 awk
或 sed
命令来处理这个问题。
它适用于单个命令,如下所示:
/afac/soq $ cd ..
/afac $ myfunc
cd
..
/afac $ touch "some file.txt"
/afac $ myfunc
touch
some file.txt
但很明显(因为数组定义中的';'),当我在一行中使用多个命令时它失败了:
$ 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 '&&'
所以为了让它工作,我必须在遇到 ;
、&&
或 ||
时将命令字符串拆分成多个部分,同时不要忘记这些标记时的情况被转义或引用,然后告别 simplicity...我什至不知道我是否能够以一种好的方式解析它,以我目前的知识sed
和 awk
...
将命令的所有参数放入数组的最干净(也是最简单)的解决方案是什么,处理引用参数、转义字符、和 多个参数的可能性单行命令?
它可能完全重复,但我没有在任何地方找到任何真正的解决方案。
虽然不是所有情况,但您可以做得更好:
function myfunc(){
set -- $(history 2 | sed 's/[ 0-9]*//;1q')
for arg
do echo "$arg"
done
}
现在我只能制作这样的东西:
#!/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
我的最终目标是以干净的方式遍历 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
的 简单性 ,因为它可以处理自动引用的参数、转义空格、glob 扩展等...所以我不不必自己用复杂的 awk
或 sed
命令来处理这个问题。
它适用于单个命令,如下所示:
/afac/soq $ cd ..
/afac $ myfunc
cd
..
/afac $ touch "some file.txt"
/afac $ myfunc
touch
some file.txt
但很明显(因为数组定义中的';'),当我在一行中使用多个命令时它失败了:
$ 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 '&&'
所以为了让它工作,我必须在遇到 ;
、&&
或 ||
时将命令字符串拆分成多个部分,同时不要忘记这些标记时的情况被转义或引用,然后告别 simplicity...我什至不知道我是否能够以一种好的方式解析它,以我目前的知识sed
和 awk
...
将命令的所有参数放入数组的最干净(也是最简单)的解决方案是什么,处理引用参数、转义字符、和 多个参数的可能性单行命令?
它可能完全重复,但我没有在任何地方找到任何真正的解决方案。
虽然不是所有情况,但您可以做得更好:
function myfunc(){
set -- $(history 2 | sed 's/[ 0-9]*//;1q')
for arg
do echo "$arg"
done
}
现在我只能制作这样的东西:
#!/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