我想从任意 shell 脚本中提取命令。我使用了 morbig(向Michael Homer表示建议!)从 shell 脚本生成 JSON 文件。
例如,这个 shell 脚本:
#!/bin/sh
echo hi
false || echo something
true && echo something
生成以下 JSON:
[
"Program_LineBreak_CompleteCommands_LineBreak",
[ "LineBreak_Empty" ],
[
"CompleteCommands_CompleteCommands_NewlineList_CompleteCommand",
[
"CompleteCommands_CompleteCommands_NewlineList_CompleteCommand",
[
"CompleteCommands_CompleteCommand",
[
"CompleteCommand_CList",
[
"CList_AndOr",
[
"AndOr_Pipeline",
[
"Pipeline_PipeSequence",
[
"PipeSequence_Command",
[
"Command_SimpleCommand",
[
"SimpleCommand_CmdName_CmdSuffix",
[
"CmdName_Word",
[ "Word", "echo", [ [ "WordName", "echo" ] ] ]
],
[
"CmdSuffix_Word",
[ "Word", "hi", [ [ "WordName", "hi" ] ] ]
]
]
]
]
]
]
]
]
],
[ "NewLineList_NewLine" ],
[
"CompleteCommand_CList",
[
"CList_AndOr",
[
"AndOr_AndOr_OrIf_LineBreak_Pipeline",
[
"AndOr_Pipeline",
[
"Pipeline_PipeSequence",
[
"PipeSequence_Command",
[
"Command_SimpleCommand",
[
"SimpleCommand_CmdName",
[
"CmdName_Word",
[ "Word", "false", [ [ "WordName", "false" ] ] ]
]
]
]
]
]
],
[ "LineBreak_Empty" ],
[
"Pipeline_PipeSequence",
[
"PipeSequence_Command",
[
"Command_SimpleCommand",
[
"SimpleCommand_CmdName_CmdSuffix",
[
"CmdName_Word",
[ "Word", "echo", [ [ "WordName", "echo" ] ] ]
],
[
"CmdSuffix_Word",
[
"Word",
"something",
[ [ "WordName", "something" ] ]
]
]
]
]
]
]
]
]
]
],
[ "NewLineList_NewLine" ],
[
"CompleteCommand_CList",
[
"CList_AndOr",
[
"AndOr_AndOr_AndIf_LineBreak_Pipeline",
[
"AndOr_Pipeline",
[
"Pipeline_PipeSequence",
[
"PipeSequence_Command",
[
"Command_SimpleCommand",
[
"SimpleCommand_CmdName",
[
"CmdName_Word",
[ "Word", "true", [ [ "WordName", "true" ] ] ]
]
]
]
]
]
],
[ "LineBreak_Empty" ],
[
"Pipeline_PipeSequence",
[
"PipeSequence_Command",
[
"Command_SimpleCommand",
[
"SimpleCommand_CmdName_CmdSuffix",
[
"CmdName_Word",
[ "Word", "echo", [ [ "WordName", "echo" ] ] ]
],
[
"CmdSuffix_Word",
[ "Word", "something", [ [ "WordName", "something" ] ] ]
]
]
]
]
]
]
]
]
],
[ "LineBreak_Empty" ]
]
我希望看到以下输出:
echo
false
echo
true
echo
...暂时忽略基本命令的任何参数、选项和参数。输出命令的顺序无关紧要。如果在输出之前很容易使它们独一无二(|sort -u
之后保存),则可以加分。
我已经做到了:
< simple.json jq flatten | grep -A2 CmdName_Word
但这感觉像是错误的方法。我想告诉jq
我“CmdName_Word”之后的“Word”之后的单词,但我不知道该怎么做。
如果您想在本地重现这些步骤(摘自https://github.com/colis-anr/morbig):
(根据您的操作系统安装 docker)
docker pull colisanr/morbig:latest
定义一个 shell 函数以便于使用:
morbig () { D=$(cd "$(dirname "$1")"; pwd) B=$(basename "$1") docker run \ -v "$D":/mnt \ colisanr/morbig:latest --as simple /mnt/"$B" }
确保包含 shell 脚本的目录可由 UID 1000 写入(docker 容器在 UID 1000 的容器内以用户“opam”身份运行)。
morbig your-shell-script-here.sh
生成的
your-shell-script-here.sh.sjson
JSON 将与 shell 脚本位于同一目录中。
此处使用的
jq
表达式在文档中的每个实体上递归并测试每个实体的类型以查看它是否为数组。对于每个找到的数组,也有第一个元素是 stringCmdName_Word
,它继续提取第二个元素的第二个元素,这是寻找的命令名称。表达式可以缩短为
...它
.[0]
在 中使用select()
,如果它可用,如果当前实体是一个数组。我也.[1][1]
直接用过select()
。