編寫(xiě)可直接執(zhí)行的 jq 腳本)
如何用 shebang 技巧exec jq --args編寫(xiě)可直接執(zhí)行的 jq 腳本【免費(fèi)下載鏈接】jqCommand-line JSON processor項(xiàng)目地址: https://gitcode.com/GitHub_Trending/jq/jq如果你把 jq 程序放在一個(gè)文件里平時(shí)只能這樣調(diào)用它jq -n -f total.jq 1 2這種寫(xiě)法有兩個(gè)問(wèn)題參數(shù)要用--arg、--args等選項(xiàng)手工傳遞而且調(diào)用者必須知道這是一段 jq 代碼。jq 官方手冊(cè)的「Comments」一節(jié)給出了一個(gè)技巧利用 jq 注釋和 shell 注釋對(duì)同一行代碼的「不同理解」在腳本里藏一行exec jq --args ...讓文件既能被sh當(dāng)作啟動(dòng)器執(zhí)行又能被jq當(dāng)作普通程序文件求值。完成之后你可以像調(diào)用任何命令行小工具一樣直接運(yùn)行./total 1 2而不用每次都敲jq前綴。前提只有一個(gè)系統(tǒng)已安裝 jq??梢杂檬謨?cè)中記載的--version選項(xiàng)確認(rèn)——它會(huì)輸出 jq 版本并以 0 退出jq --version技巧原理同一行代碼兩種解釋jq 支持用#寫(xiě)注釋#不在字符串內(nèi)之后的內(nèi)容直到行尾都被忽略。手冊(cè)特別指出如果行尾前面有奇數(shù)個(gè)反斜杠\下一行也會(huì)被當(dāng)作注釋的一部分而忽略。這就是技巧的核心對(duì) jq 來(lái)說(shuō)行尾帶\的#注釋會(huì)把下一行也吞掉所以exec那一行對(duì) jq 只是注釋求值時(shí)被忽略對(duì)sh來(lái)說(shuō)行尾的反斜杠不會(huì)延續(xù)注釋所以exec那一行是真正執(zhí)行的 shell 語(yǔ)句。sh執(zhí)行到exec jq --args -MRnf -- $0 $時(shí)會(huì)用 jq 解釋器替換掉自身進(jìn)程以-M -R -n -f --args選項(xiàng)啟動(dòng) jq求值當(dāng)前文件$0并把傳給腳本的其余參數(shù)$原樣交給 jq。手冊(cè)給出的展開(kāi)過(guò)程是當(dāng)腳本以total 1 2被調(diào)用時(shí)實(shí)際執(zhí)行的是/bin/sh -- /path/to/total 1 2隨后sh運(yùn)行exec jq --args -MRnf -- /path/to/total 1 2。涉及的相關(guān)選項(xiàng)含義均出自手冊(cè)「Options」一節(jié)選項(xiàng)作用--args--args之后的剩余參數(shù)作為位置字符串參數(shù)傳入jq 程序中以$ARGS.positional[]訪問(wèn)-f/--from-file從文件讀取過(guò)濾器此時(shí)過(guò)濾器參數(shù)被解釋為文件名而不是程序源碼-n/--null-input不讀取任何輸入過(guò)濾器以null為輸入運(yùn)行一次-R/--raw-input不把輸入解析為 JSON每行文本作為一個(gè)字符串傳給過(guò)濾器-M/--monochrome-output關(guān)閉彩色輸出--終止選項(xiàng)解析之后的參數(shù)不再被當(dāng)作選項(xiàng)因?yàn)?-args傳進(jìn)來(lái)的是字符串jq 程序內(nèi)部需要用tonumber自行完成數(shù)值轉(zhuǎn)換——這也是下面示例中出現(xiàn)try tonumber catch false的原因。編寫(xiě)腳本手冊(cè)給出的 total 示例下面這段腳本是手冊(cè)中的完整示例它是一個(gè)求和工具接收若干數(shù)字參數(shù)沒(méi)有參數(shù)時(shí)則從標(biāo)準(zhǔn)輸入逐行讀取輸出它們的總和。請(qǐng)把它原樣保存為一個(gè)文件例如total不需要.jq后綴因?yàn)樗峭ㄟ^(guò)-f作為頂層程序文件傳入 jq 的#!/bin/sh -- # total - Output the sum of the given arguments (or stdin) # usage: total [numbers...] # \ exec jq --args -MRnf -- $0 $ $ARGS.positional | reduce ( if . [] then inputs else .[] end | . as $dot | try tonumber catch false | if not or isnan then json total: Invalid number \($dot).\n | halt_error(1) end ) as $n (0; . $n)腳本分兩部分看shell 頭部前 5 行第 1 行#!/bin/sh --指定由/bin/sh啟動(dòng)--保證后面的腳本路徑不會(huì)被sh誤解析為選項(xiàng)第 2、3 行是說(shuō)明性注釋對(duì) sh 和 jq 都是注釋第 4 行# \以反斜杠結(jié)尾把第 5 行的exec語(yǔ)句在 jq 視角下「藏」成了注釋但對(duì)sh可見(jiàn)。jq 程序第 5 行之后$ARGS.positional是位置參數(shù)數(shù)組數(shù)組為空時(shí)改用inputs從標(biāo)準(zhǔn)輸入逐行讀入-R下每行是一個(gè)字符串每個(gè)值經(jīng)tonumber轉(zhuǎn)換不是合法數(shù)字not為false或isnan時(shí)輸出 JSON 格式的錯(cuò)誤消息并調(diào)用halt_error(1)以退出碼 1 終止。賦予執(zhí)行權(quán)限并運(yùn)行要「直接執(zhí)行」這個(gè)文件還需要給它加上可執(zhí)行權(quán)限。以下命令只影響這一個(gè)文件chmod x total然后按普通命令行工具的方式調(diào)用./total 1 2手冊(cè)示例注釋寫(xiě)明該腳本的用途是「Output the sum of the given arguments (or stdin)」因此這次調(diào)用應(yīng)輸出 1 與 2 的和即3。驗(yàn)證方式正常路徑運(yùn)行./total 1 2若輸出3說(shuō)明 shebang 展開(kāi)、--args參數(shù)傳遞和求和邏輯都工作正常。等價(jià)命令對(duì)照根據(jù)前面對(duì)展開(kāi)過(guò)程的說(shuō)明腳本調(diào)用最終等價(jià)于直接運(yùn)行jq --args -MRnf total 1 2兩條命令的輸出應(yīng)當(dāng)一致可以用它來(lái)隔離問(wèn)題——如果直接命令能跑通而./total不行問(wèn)題出在 shebang 頭部文件權(quán)限、exec行是否被意外改動(dòng)。錯(cuò)誤路徑傳入非數(shù)字參數(shù)例如./total 1 abc。示例程序會(huì)輸出total: Invalid number abc.形式的 JSON 錯(cuò)誤消息json生成、經(jīng)halt_error(1)打印到 stderr 并終止。手冊(cè)對(duì)halt_error(exit_code)的說(shuō)明是以給定的退出碼此處為 1默認(rèn)值是 5停止程序。可用 shell 的$?確認(rèn)退出碼./total 1 abc echo $? # 期望輸出 1限制與注意點(diǎn)這個(gè)技巧只能「藏住」exec這一行反斜杠行延續(xù)只能把緊鄰的下一行并入注釋因此整個(gè) jq 程序必須從exec行的下一行開(kāi)始且前面不能出現(xiàn)任何對(duì) jq 非法而對(duì) sh 又必須執(zhí)行的語(yǔ)句。第 1 行必須是#!/bin/sh --形式由/bin/sh啟動(dòng)依賴sh中反斜杠不延續(xù)注釋的行為把它改成直接指向jq的路徑會(huì)讓exec行被 jq 當(dāng)作注釋忽略腳本就不會(huì)工作了。--args傳進(jìn)來(lái)的是字符串參數(shù)程序必須自己處理類型轉(zhuǎn)換與非法值這一點(diǎn)由示例中的try tonumber catch false分支負(fù)責(zé)改寫(xiě)腳本時(shí)不要?jiǎng)h掉。完整的注釋規(guī)則包括奇數(shù)/偶數(shù)個(gè)反斜杠對(duì)行延續(xù)的影響可以在 jq 官方手冊(cè) 的「Comments」一節(jié)查閱本文的示例即出自該節(jié)?!久赓M(fèi)下載鏈接】jqCommand-line JSON processor項(xiàng)目地址: https://gitcode.com/GitHub_Trending/jq/jq創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考