Sed

從 grep 的輸出中刪除匹配模式?

  • April 13, 2022

使用 bash,我正在執行:declare -p | grep 'declare -- '列印整行。我想列印那些相同的行,但我想排除匹配本身。即,我可以... | grep pattern | sed 's/pattern//'作為單個命令執行嗎?這將與-o選項相反。

我的命令輸出這個:

...
declare -- MAX_CONNECTIONS_PER_SERVER="6"
declare -- OPTERR="1"
declare -- OSTYPE="linux-gnu"
...

但我想輸出這個:

...
MAX_CONNECTIONS_PER_SERVER="6"
OPTERR="1"
OSTYPE="linux-gnu"
...

通常情況下,我只是將它傳送到sed,但巧合的是,我今天想這樣做兩次。我查看了手冊頁,但沒有看到任何可以執行此操作的選項。

在匹配模式之後只返回一行的一部分是一個非常相似的問題。也許它甚至是重複的。有人可能會爭辯說我的範圍更窄一些:可以保證我正在抓取的模式和我正在刪除的模式是相同的。我想刪除x. 問題要刪除.*x

如果可用,請使用grep -P

declare -p | grep -Po 'declare -- \K.*'

請注意,您的方法通常不會很好地工作,因為變數可能包含您將切斷的換行符grep並獲得語法錯誤。

參見例如:

declare -- IFS="    
"

那應該是:

declare -p | sed -n 's/^declare -- //p'

但是這種解析輸出的方法declare -p是有缺陷的。

例如,如果環境中有 a VAR=$'\ndeclare -- reboot #',並且您將該輸出提供給 shell 進行解釋,該怎麼辦?

另請注意,對於已聲明但未分配任何值的變數,將bash列印:declare -- VARNAME,因此在 之後declare reboot,上述程式碼也會輸出reboot

您可以將其更改為:

declare -p | LC_ALL=C sed -n 's/^declare -- \(.*=\)/\1/p'

限制為分配的變數,但這仍然不能解決包含換行符的變數的問題(即使僅針對$TERMCAP變數也很常見)。

相反,您可以使用這種 hack:

(
 export LC_ALL=C
 eval '
   declare()
     if [[ $1 = -- ]]; then
       printf "%s=%q\n" "${2%%=*}" "${2#*=}"
     fi'"
   $(declare -p | sed 's/[][()]/\\&/g')"
)

在我們重新定義為一個函式之後,我們在哪裡評估declare -p我們轉義的地方的輸出(,並在數組和關聯數組表示中使用,如果第一個參數是 ,則列印它的第二個參數。使用風險自負,過去已知 bash 的輸出對於評估是不安全的,添加轉義也可能會增加複雜性,特別是對於它們接受的行長度有限制的實現。)``[``]``declare``--``declare -p``sed``sed


在 中zsh,你可以這樣做:

typeset ${(k)parameters[(R)scalar]}

列印標量變數的定義並且沒有任何屬性(甚至不是special也不是linked),這似乎是您的意圖。

typesetsilent但是請注意,如果在函式中呼叫(在這種情況下,它將所有這些變數聲明為本地變數)或啟用該選項,則它不起作用。

另一種可以解決這個問題並讓您更好地控制如何引用值的方法是:

() for 1 do print -r -- $1=${(Pq+)1}; done ${(k)parameters[(R)scalar]}

q+給出與 . 使用的引用風格相似的引用風格typeset。如果您打算在 shell 中使用該輸出(可能不是 zsh,或者不是來自同一版本,或者不在相同的語言環境或 OS/libc 中),請使用qq安全的引用樣式。

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