Linux

在文件的每一行中查找一個字元串,然後使用 bash 替換同一行中的另一個字元串

  • May 6, 2022

這是我的腳本:

#! /bin/bash

# C-band Edit
dqt='"'
str5="polarization=${dqt}2${dqt}"
for x in {3600..4200} do;
   sed -i "/$str5.*$x/s/$x/$((x-600))/" satellites.xml
done

我想做的就是在satellites.xml中有str5的所有行上用3600到4200之間的x-600替換數字x,但上面的腳本給了我語法錯誤

我突然想到你不是指文字字元串x-600,你的意思是“從 3600 到 4200 之間的每個值中減去 600”。在這種情況下,使用 perl,而不是 sed:

echo "$str5. foo bar 3200 3964 4155 4200 4255" |
 perl -p -e "if (/$str5/) {s/3[6789]\d\d|4[01]\d\d|4200/$&-600/eg}"
polarization="2". foo bar 3200 3364 3555 3600 4255

這使用 perl 的/e正則表達式修飾符來導致右側 ( $&-600) 被評估為 perl 表達式$&是一個包含匹配值的 perl 變數,因此$&-600意味著從該值中減去 600。

如果那是您真正想要的,我會在下面留下我的原始答案。也因為它有有用的解釋,這些解釋仍然與上面的 perl 答案有些相關。

與 sed 一樣,perl 有一個-i就地編輯選項,因此您可以將其直接應用到您的 satellites.xml 文件中。詳情請參閱man perlrun

perl -i -p -e "if (/$str5/) {s/3[6789]\d\d|4[01]\d\d|4200/$&-600/eg}" satellites.xml

另外值得注意的是:在處理 XML 文件時,您可能應該使用 XML 解析器。幸運的是,perl 有幾個可供選擇,例如XML::Parser或集合libxml-perl


我沒有您實際輸入的範例,因此我製作了一個範例來展示什麼會改變,什麼不會:

str5='polarization="2"'

echo "$str5. foo bar 3500 3964 4155 4200 4255" | 
 sed -e "/$str5/ {s/3[6-9][0-9][0-9]/3-600/g; s/4[01][0-9][0-9]/4-600/g; s/4200/4-600/g}"
polarization="2". foo bar 3500 3-600 4-600 4-600 4255

大致翻譯成英文,就是“如果目前行包含$str5( polarization="2"),則對其應用這三個s///操作”。

筆記:

  • 無需從 3600..4200 循環。這將在一次執行中進行所有更改sed,而不是 600 次執行。

  • 您希望更改 3600-4200 的值。這意味著您需要 3 次搜尋和替換操作:

    • 一個用於 3600-3999
    • 一個用於 4000-4199
    • 一個正好 4200
  • 或者,這可以通過兩個s///操作來完成,將最後兩個合併為一個:

 sed -e "/$str5/ { s/3[6-9][0-9][0-9]/3-600/g; s/4[01][0-9][0-9]\|4200/4-600/g }"
  • 可能還有許多其他方法可以優化正則表達式,但是您這樣做的次數越多,將來閱讀和修改它們的難度就越大。
  • 3964, 4155,4200並被更改。 35004255不是,它們超出了所需的範圍。
  • [0-9]在某些語言環境(該範圍內還有其他字元)中不會像您期望的那樣工作。我不確切知道哪些語言環境,但我已經看到它經常被提及,足以知道[0-9]不能完全依賴它。如果這影響到您,您可以使用[[:digit:]]代替[0-9],或使用perl -p代替sed(因此您可以使用\d代替[0-9])。同樣適用於 range [6-9],請[6789]改用。
  • 最後,要非常小心你放入$str5變數中的內容。因為它被插入到sed命令中,所以很容易破壞 sed 腳本(例如,如果$str5包含 a /,它將破壞/$str5/匹配)。sed 不知道它的腳本部分來自一個 shell 變數,它所看到的只是它被賦予執行的腳本。

此外,整個字元串將被sed 解釋為正則表達式- 這意味著正則表達式元字元不會被解釋為文字字元,除非它們使用\. eg.將被解釋為“任何字元”而不是文字點,除非它被轉義為\.

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