Json

從 morbig 生成的 JSON 文件中提取 CmdName_Word - Word

  • April 7, 2022

我想從任意 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):

  1. (根據您的作業系統安裝 docker)
  2. docker pull colisanr/morbig:latest
  3. 定義一個 shell 函式以便於使用:
morbig () {
  D=$(cd "$(dirname "$1")"; pwd)
  B=$(basename "$1")
  docker run \
    -v "$D":/mnt \
    colisanr/morbig:latest --as simple /mnt/"$B"
}
  1. 確保包含 shell 腳本的目錄可由 UID 1000 寫入(docker 容器在 UID 1000 的容器內以使用者“opam”身份執行)。
  2. morbig your-shell-script-here.sh
  3. 生成的your-shell-script-here.sh.sjsonJSON 將與 shell 腳本位於同一目錄中。
$ jq -r '.. | select(type == "array" and .[0] == "CmdName_Word") | .[1][1]' file
echo
false
echo
true
echo

此處使用的jq表達式在文件中的每個實體上遞歸併測試每個實體的類型以查看它是否為數組。對於每個找到的數組,也有第一個元素是 string CmdName_Word,它繼續提取第二個元素的第二個元素,這是尋找的命令名稱。

表達式可以縮短為

jq -r '.. | select(.[0]? == "CmdName_Word")[1][1]' file

…它.[0]在 中使用select(),如果它可用,如果目前實體是一個數組。我也.[1][1]直接用過select()

引用自:https://unix.stackexchange.com/questions/698270