Sed

如何使用 sed 顯示第一個空白行和最後一行之間的行?

  • August 25, 2020

我正在嘗試在 shell 腳本中解析來自我的 Web 伺服器的響應。這是回應:

HTTP/1.0 404 NOT FOUND
Content-Length: 223
Content-Type: application/json
Last-Modified: Fri, 21 Aug 2020 15:24:23 GMT
Cache-Control: public, max-age=43200
Expires: Sat, 22 Aug 2020 08:04:19 GMT
ETag: "1598023463.02863-223-4034336499"
Date: Fri, 21 Aug 2020 20:04:19 GMT
Server: Werkzeug/1.0.1 Python/3.8.5

{
   "message": {
       "status": "404",
       "message": "Not Found"
   }
}

我將其分配給一個變數:

% foo="$(curl -i http://127.0.0.1/404)"

我想要一個用於狀態程式碼和一個用於響應正文,而不是一個變數。獲取狀態碼很容易:

% echo "$foo" | head -n 1

困難的部分是使用 sed 過濾掉標題。基於Bruce Barnett 的精彩 Sed gymoire,我認為這會起作用:

% echo "$foo" | sed '1,/^$/ d'

或者:

% echo "$foo" | sed -n '/^$/,$ p'

但是,這兩個命令的結果都沒有。我不明白為什麼。

萬一這很重要,我正在使用來自 Homebrew 的 zsh 5.8 和 GNU sed 4.8 以及來自 Mac OS 的 curl 7.64.1。

問題是 curl 的輸出中有輸入符(CR),所以模式/^$/永遠不匹配,因為每一行都有一個 CR,所以不是空的。

有幾件事可以做,要麼刪除 CR,要麼考慮它們。

foo="$(curl -i http://127.0.0.1/404 | tr -d '\r')"

將刪除它們,然後

printf '%s\n' "$foo" | sed '1,/^$/d'

將起作用,或者如果我沒有使用刪除 CR 則使用tr

printf '%s\n' "$foo" | sed $'1,/^\r$/d'

由於 zsh 可以進行字元串替換,我傾向於使用

printf '%s\n' "${foo#*$'\r\n\r\n'}"

或者

printf '%s\n' "${foo#*$'\n\n'}"

取決於我是否曾經tr剝離 CR,以保存 sed 程序。

但是有一個警告:命令替換會刪除所有尾隨換行符(不是輸入符)。HTTP 響應是<header1>CRLF...<headern>CRLFCRLF<body>. 如果<body>為空,$foo將僅包含<header1>CRLF...<headern>CRLFCR<header1>CRLF...<headern>如果我們已刪除 CR。在這些情況下,*$'\r\n\r\n'or*$'\n\n'將不匹配,並且標題不會被刪除。

在任何情況下,要列印後跟換行符的任意字元串,語法是:

printf '%s\n' "$foo"  # POSIX
print -r - "$foo"     # ksh/zsh
echo -E - "$foo"      # zsh

如果包含反斜杠(在 json 中很常見)或某些以開頭的值(json 不應該是這種情況) ,則not echo "$foo"which 不能正常工作。$foo``-

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