Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
以智能和干净的方式拆分bash命令参数_Bash_Shell_Awk_Scripting_Split - Fatal编程技术网

以智能和干净的方式拆分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

我的最终目标是以一种干净的方式迭代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
}
/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 '&&'
因此,要使其工作,我必须在
时将命令字符串拆分为多个部分
&&
|
时,不会忘记转义或引用这些令牌的情况,然后告别简单性。。。我甚至不知道我是否能够以一种好的方式解析它,以我目前关于
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
中删除所有特殊字符,例如:
[].*^.+&$!%
。检查更新版本。非常好的主意;我会稍微调整字符列表(特别是添加分号),但它做得相当好!