2017-08-10 38 views
0

我試圖在使用jq的shell腳本程序中解析json文件。使用JQ在shell腳本中迭代JSON對象

的JSON結構看起來是這樣的:

{ 
    "items":[ 
     { 
     "playlists":[ 
      { 
       "title":"Level One Title", 
       "courses":[ 
        { 
        "title":"Level One Course One Title", 
        "lessons":[ 
         { 
          "title":"lesson 1 title", 
          "url":"lesson 1 url" 
         }, 
         { 
          "title":"lesson 2 title", 
          "url":"lesson 2 url" 
         } 
        ] 
        }, 
        { 
        "title":"Level One Course Two Title", 
        "lessons":[ 
         { 
          "title":"lesson 1 title", 
          "url":"lesson 1 url" 
         }, 
         { 
          "title":"lesson 2 title", 
          "url":"lesson 2 url" 
         } 
        ] 
        } 
       ] 
      }, 
      { 
       "title":"Level Two Title", 
       "courses":[ 
        { 
        "title":"Level Two Course One Title", 
        "lessons":[ 
         { 
          "title":"lesson 1 title", 
          "url":"lesson 1 url" 
         }, 
         { 
          "title":"lesson 2 title", 
          "url":"lesson 2 url" 
         } 
        ] 
        }, 
        { 
        "title":"Level Two Course Two Title", 
        "lessons":[ 
         { 
          "title":"lesson 1 title", 
          "url":"lesson 1 url" 
         }, 
         { 
          "title":"lesson 2 title", 
          "url":"lesson 2 url" 
         } 
        ] 
        } 
       ] 
      } 
     ] 
     } 
    ] 
} 

因爲我是一名iOS開發者,我寫了一個模擬件的雨燕代碼會達到我想要的。它看起來像這樣:

for level in levels { 
    let title = level["title"] 
    //TODO: create a folder with title and set as pwd 
    for course in level["courses"] { 
     let courseTitle = course["title"] 
     //TODO: create a folder with title and set as pwd 
     for lesson in course["lessons"] { 
      let title = lesson["title"] 
      let videoURL = lesson["url"] 
      //TODO: download video in current folder with title 
     } 
    } 
} 

levelsDictionariesArraylevel是那些Dictionaries之一。每個級別包含Arraycourses,其中每個是Dictionary,包含Arraylesson字典。

來自Swift,我發現jq的語法非常混亂,尤其是將函數返回值賦值給變量。這裏是我得到多遠:

levels=$(jq ".items[0].playlists" data.json) 
for level in $levels 
do 
    title=$($level | jq ".title") 
    echo $title 
done 

這似乎並沒有工作。我想我的邏輯使用for循環在這裏是完全錯誤的。任何想法如何完成?

+1

提供樣本輸入和樣本輸出會很有幫助,所以人們不需要通讀您的代碼。另外,還有很難從代碼中得出的上下文(例如,頂級'levels'是一個列表還是一個字典?) –

+0

順便說一句,你應該只用一個程序調用'jq'一次做所有的迭代 - 也就是說循環應該在jq代碼中,而不是shell腳本。 –

+0

(和'在$ levels中的水平'是bug的殼 - 見http://mywiki.wooledge.org/DontReadLinesWithFor) –

回答

2

代碼提取標題和URL到不同的shell變量可能看起來像:

jq_program=' 
.items[].playlists[]   # we only care about playlist contents 
| .title as $level_title  # store the level title before recursing 
| .courses[]     # ...into elements of the array in .courses... 
| .title as $course_title  # repeat to store the course title 
| .lessons[]     # ...before recursing into the lesson... 
# ...and emitting the stored level and course titles, plus the lesson title and url 
| [$level_title, $course_title, .title, .url] | @tsv        
' 

while IFS=$'\t' read -r level_title course_title lesson_title lesson_url <&3; do 
    mkdir -p -- "$level_title/$course_title" 
    ## For test purposes, just store the URL in the file 
    printf '%s\n' "$lesson_url" >"$level_title/$course_title/$lesson_title" 
    ## If we had real data, we might instead be running something like: 
    # curl -o "$level_title/$course_title/$lesson_title" "$lesson_url" 
done 3< <(jq -r "$jq_program" <input.json) 

在這裏,我們有jq做遞歸的工作,並散發出平(製表符分隔)列表,閱讀該列表在bash中。出於顯而易見的原因,這僅適用於內容不能包含製表符的情況;如果需要使用任意字符串(在bash可以存儲的範圍內),可以從jq生成NUL分隔的輸出,但需要使用stedolan/jq#1271中討論的其中一種解決方法。

請參閱BashFAQ #1討論我們在此處使用的技術,以從jq的輸出中讀取製表符分隔的數據。

+0

您錯過了每門課程中的「課程」層。另外,我不需要列表中的名稱,我需要創建類似於JSON的文件夾結構。 – damjandd

+1

@damjandd,請參閱shell腳本中的'mkdir'?它是從JSON創建目錄結構,從jq發出的列表中讀取數據,然後將'curl'下載到該目錄中。 –

+0

@CharlesDuffy對不起,我錯過了。 – damjandd