awk 單行指令 awk '{ print "\"" $0 "\"" }' file 會把純文字清單的每一行包裹在雙引號中,這個單一指令正是「awk 為每一行加上引號」會在同事把五十個 ID 貼進聊天室時成為常見搜尋的原因。它速度很快、語法簡潔,對於沒有內嵌標點的乾淨 ASCII 清單,它能產生開發者想要的精確輸出。然而一旦某個值包含雙引號、單引號、撇號、逗號,或是目的格式視為特殊的任何字元,問題就會開始出現。awk 單行指令並沒有 JSON 字串字面值、SQL 字串常值,或 RFC 4180 CSV 欄位的概念,因此它無法按照每種格式實際要求的方式跳脫內容。結果就是一份乍看之下正確、卻在首次使用時就把解析器弄壞的清單。一個遵循每種格式已公布跳脫規則的引號工具,能產出可直接貼上查詢主控台、JSON 文件,或試算表匯入的輸出,不需要手動清理,也不需要再跑一輪尋找取代。

awk add quotes to each line
awk add quotes to each line

為什麼 awk 模式無法滿足真實的清單

典型的 awk 管線只處理前綴和後綴。它不知道你的目的端是 JSON 陣列、SQL WHERE id IN (...) 子句,還是 CSV 資料列,也沒有內建概念去理解這些格式如何處理值中的引號。這項限制會在輸入內容除了純識別符之外還含有其他東西時首次顯現。

想像聊天訊息中三行看似無害的內容:O'Brien、say "hi",以及 line, with comma。一個只加上外層引號的 awk 管線會產生 "O'Brien"、"say "hi""、以及 "line, with comma"。這三行在這三種目標格式中,沒有一個是有效的字串。第一個會破壞 SQL,因為單引號提早結束了字面值。第二個會破壞 JSON,因為內部的雙引號沒有跳脫。第三個會破壞 CSV,因為未跳脫的逗號會被視為欄位分隔符,導致欄位數量錯誤。這個問題並不隱晦:awk 方法以正確性換取簡潔,而下游解析器要求的正是正確性。

三步驟為每一行加上引號

  1. 把你的清單(每行一個項目)貼到輸入欄位中。
  2. 點選符合目的端的預設值:JSON arraySQL IN clauseCSV row,或 Plain quotesBacktick 選項涵蓋 JavaScript 樣板字面值,並會跳脫插值起始符,因此貼上的內容無法注入運算式。
  3. 複製可直接貼上的輸出。如果需要更細部的控制,可開啟逐行控制項,設定引號樣式、分隔符、最後一行的結尾分隔符、是否跳脫、是否略過空白行,以及逐行修剪,然後再複製。

整個流程只需一次點選,結果會回報處理了多少行,因此可以與原始清單進行數量核對。這個工具對自己的輸出再次執行時,會刻意再包裹一層,因為引號工具無法判斷既有的引號是內容,還是前一輪的包裹;若要套用新設定,請從原始清單重新開始。

每個預設值實際做了什麼

這四個預設值並非同一個包裹器的四種外觀。它們各自實作了不同的已公布規則,規範如何跳脫內嵌字元,而這正是手工撰寫的 awk 單行指令無法複製的部分。

預設值 遵循的標準 內嵌引號的處理方式 包裹引號與周邊語法
JSON array RFC 8259 \" (反斜線跳脫);反斜線本身會加倍 雙引號;以 [ ] 包裹
SQL IN clause ISO SQL / PostgreSQL / SQLite '' (兩個單引號,不使用反斜線) 單引號;以 ( ) 包裹
CSV row RFC 4180 "" (兩個雙引號) 雙引號;資料列以單行輸出
Backtick (template literal) JavaScript 樣板字面值語法 內嵌的反引號和 ${ 會被跳脫 反引號

SQL 規則值得特別注意,因為它經常讓來自 JSON 思維的人感到意外。在 JSON 中,跳脫使用的是反斜線。在 SQL 中,PostgreSQL 和 SQLite 採用的標準規則是將單引號加倍,而不是加上反斜線,因此值 it's 在有效的 WHERE col IN (...) 清單中會變成 'it''s'。CSV 規則是第三種不同的模式:欄位以雙引號包裹,內嵌的雙引號會被替換為兩個雙引號,這就是為什麼產生的資料列一定會以單行輸出。這三種規則並非風格選擇——它們是解析器實際實作的規則——而預設值正是將這些差異編碼進去。每個預設值都對齊到其所引用的標準:CSV 的 RFC 4180,以及 SQL 字串常值的 PostgreSQL 詞法結構文件

結尾分隔符切換的說明

預設情況下,最後一行不會帶有結尾逗號,因為在多數情境中,帶有結尾分隔符的 JSON 陣列或 SQL IN 清單會造成語法錯誤。這對於可直接貼上的輸出是正確的預設值。當目標格式確實需要結尾分隔符時(例如,將多個引號清單串接成更大的結構),此切換會將其加上。這項控制是明確的,讓選擇清晰且可逆,而不是埋藏在對目的端的隱含假設之中。

預設值所能做到的一切,也都可作為個別控制項使用:引號樣式(含不引號)、分隔符(最後一行是否含結尾分隔符)、是否跳脫、是否略過空白行,以及逐行修剪。因此,同一個輸入在 JSON 預設值下,只要調整控制項,就能以四種不同的方式加上引號。

重新執行時會發生什麼,以及原因

有個行為會被明確記錄,而不是被隱藏:對工具自己的輸出再次執行,會再包裹一層。引號工具無法判斷輸入中既有的引號是內容,還是前一輪的包裹,因此安全的做法就是再包裹一次。如果需要不同的預設值或設定,回到正軌的方式就是從原始清單重新開始。同樣的陷阱也會出現在 shell 管線中——每經過一個階段,包裹引號就會累加一層——這正是應該把引號處理這一步驟保持為單一、明確操作的原因之一。

awk 仍然是合適工具的情境

對於這項任務,awk 並未過時。當工作發生在 Unix 管線之中、輸入保證是乾淨的 ASCII、目的地格式尚未確定,或是引號處理是 awk 正在驅動的更大轉換中的一個步驟時,它就是合適的工具。一旦目的地格式具有已公布的跳脫規則——JSON、SQL、CSV、JavaScript 樣板字面值——而輸入內容又比識別符和數字更複雜時,一個遵循正確標準的引號工具會更快、更不易出錯,也更容易稽核。跳脫規則是公開的,預設值對齊到定義它們的標準,產生的清單可直接貼上查詢主控台、編輯器,或試算表匯入,不需再進行一次尋找取代。基於瀏覽器的 為每一行加上引號 工具,以一次點選處理最常見的目的地,並將資料保留在本機:輸入上限為一百萬個字元,以單一線性處理程序執行,因此即使是很長的清單也能瞬間回傳,而且不會上傳或儲存任何資料。

清單相關的文字工具

如果你即將加上引號的清單來自聊天訊息或試算表匯出,值得先將其通過重複行移除工具和清單比對工具處理。在加上引號之前先清理清單,才能讓輸出保持為真正唯一的值集合,這通常才是 JSON 測試資料、SQL IN 子句,或環境白名單預期要呈現的內容。如果你實際需要的包裹方式不是引號,而是任意文字(例如,將每一行用 HTML 標籤或固定前綴包起來),那麼專門的 前綴與後綴工具 會更合適,因為規範引號處理的規則,正是本頁面旨在編碼的內容。

相關閱讀:如何在 Word 中將換行符號變更為 \n 或實際換行

相關閱讀:Bash 為每一行加上引號:Sed、Awk 和 Xargs