Bash

用變數替換文件內容中匹配的正則表達式

  • May 17, 2022

我想做以下事情

  1. ^[ \t]*services:[ \t]*使用模式 ( )搜尋文件內容
  2. 如果找到,將模式替換為字元串(在變數中)
  3. 否則,將字元串(在變數中)附加到文件末尾

我被困在第 2 步,腳本的第 2 步將services:在文件中替換為${serviceLoopBack}. 我的sed命令有什麼問題?

測試腳本

#!/bin/bash
set -e

destfile=config.yml

serviceLoopBack="services:|NL|- name: loopback-service|NL||FS||FS|url: http://127.0.0.1:12345|NL||FS||FS|routes:|NL||FS||FS|- name: loopback-test-route"
serviceLoopBackWithFrontSpace="|NL||NL|$serviceLoopBack"

if grep -E "^[ \t]*services:[ \t]*" $destfile
then
   # service tag found, replace target string
   sed -i -e 's/^[ \t]*services:[ \t]*/${serviceLoopBack}/g' $destfile
else
   # service tag not found, append at end of file
   echo $serviceLoopBackWithFrontSpace >> $destfile
fi

# replace separator 1 to new line
sed  -i -e 's/|NL|/\n/g' $destfile

# replace separator 2 to space
sed  -i -e 's/|FS|/ /g' $destfile

問題是在您的第二次sed呼叫中,您已將程序括在單引號 ( ' ... ') 中。雖然這是推薦的做法,但單引號會阻止 shell 擴展 shell 變數,例如${serviceLoopBack},因此文本將保持逐字不變,而不是被 shell 變數的內容替換。

一種可能性是使用雙引號而不是單引號,如

sed -i -e "s,^[ \t]*services:[ \t]*,${serviceLoopBack}," "$destfile"

或者,使用以下命令將表達式組裝到sedshell 變數中printf

printf -v prog 's,^[ \t]*services:[ \t]*,%s,' "$serviceLoopBack"
sed -i -e "$prog" "$destfile"

請注意,我使用,as 分隔符而不是/,因為您的替換文本/也包含,否則會混淆sed. 另外,我省略了該g選項,因為我假設每行只有一個匹配項。

無論如何,您可能都想查看您的 shell 腳本中的引用,例如,請參閱此答案以了解原因。

但是,如果sed不是嚴格要求,幾乎可以將整個 shell 腳本替換為一個awk程序(這樣更快):

awk -v slb="services:|NL|- name: loopback-service|NL||FS||FS|url: http://127.0.0.1:12345|NL||FS||FS|routes:|NL||FS||FS|- name: loopback-test-route" \
'/^[ \t]*services:/{$0=slb;f=1}
 {gsub(/\|NL\|/,"\n"); gsub(/\|FS\|/," ")} 1; END{if (!f) {print "\n\n" slb}}' "$destfile"
  • awk這將在變數中導入“服務環回”規範slb
  • 然後它將檢查是否有任何行與services:模式匹配,如果是,則將整行替換為儲存在slb其中的字元串(我推斷這是您實際想要實現的)。同時,將標誌設置f為 1。
  • 使用gsub(),用|NL|換行符替換所有出現的 ,|FS|用空格替換所有出現的 。
  • 看似“流浪”的1指示awk列印目前行,包括到目前為止所做的所有修改。
  • 最後,如果f仍未設置,則將“服務循環返回”行附加到前導模式(但是,已經轉換為\n\n)。

請注意,除非您有理解該選項awk的實現,否則不會就地編輯文件。您可能必須將輸出重定向到臨時文件,然後用臨時文件替換。awk``-i inplace``$destfile

但是,總而言之,由於您使用的是結構化語言 (YAML),因此使用專用解析器(例如,yq代替面向行的文本處理工具)可能是值得的。

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