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