簡體   English   中英

Bash:將匹配的正則表達式替換為另一個文件的第n行

[英]Bash: replace matching regex with nth line from another file

我有兩個文件。

文件一是TXT並包含字符串,每行一個。

文件二是一個XML,有幾個條目,如下所示:

<data name="Btn:Cancel" xml:space="preserve">
    <value>Cancel</value>
    <comment>Original English: Cancel</comment>
  </data>

我需要將XML文件中的VALUE值替換為來自文件一的相應字符串:因此,第一次出現的VALUE將被文件1中的第一行替換,XML文件中第二次出現的VALUE將被替換為文件一的第二行,依此類推。

我嘗試過幾件事(基本上都是使用sed)而我的最后一槍是

while read line           
do
    echo $count
    echo $line
    sed "s_<value>.*</value>_<value>$line</value>_$count" file.xml > results.xml
    ((count++))
done < file.txt

但它對results.xml文件沒有任何作用:(

這可能適合你(GNU sed):

sed -n '/<value>/=' file.xml |
sed 'R file.txt' | 
sed 'N;s/\(.*\)\n\(.*\)/\1s#<value>[^<]*#<value>\2#/' |
sed -f - file.xml > file1.xml

此解決方案:查找xml文件中每個<value>行的行號。 然后將txt文件中的值附加到每個行號。 將這兩者組合成一個sed指令,其中包含每個<value>的地址和<value> 然后將生成的sed命令應用於xml文件以生成結果。

像這樣修改你的腳本

count=1
# test.xml is your file
cat test.xml | tr "\n" "\t" > test2.xml
while read line
do
    echo $count
    echo $line
    sed -i " s_<value>[^<]*</value>_<value>$line</value>_${count}; " test2.xml
    ((count++))
done < file.txt
cat test2.xml | tr "\t" "\n" >test3.xml
  • 初始化計數
  • 不同的正則表達式( [^>]*
  • 使用tr將test.xml轉換為一個長行,使用帶有number flagsed s命令可以處理
  • 使用另一個tr來轉換長線

使用awk的解決方案:

awk '/<value>.*<\/value>/{getline newval<"file.txt";sub(/[^>]*<\/value>/,newval"</value>")}1' file.xml

或者,更詳細一點:

#!/usr/bin/awk -f

# If we match the <value></value> line
/<value>.*<\/value>/ {

    # Read next line from txt file
    getline newval < "file.txt"

    # Substitute value between tags
    sub(/[^>]*<\/value>/, newval "</value>")
}

# For all lines: print
{ print }

作為一個好公民,我會提到用專用XML解析器以外的工具解析XML通常不是一個好主意。 命令行XML解析可以使用,例如,

您可能希望使用sed命令的--in-place (或-i )參數,如下所示:

sed -i 's/hello/test/' your_file

這將修改文件。

希望這可以幫助 !

我建議使用真正的編程語言,比如Perl。 例如:

perl -e ' use warnings;
          use strict;

          open my $new_values_fh, "<", "file.txt" or die;

          while (<>) {
              if (m{<value>}) {
                  my $new_value = <$new_values_fh>; chomp $new_value;
                  s{(<value>).*?(</value>)}{$1$new_value$2};
              }
              print;
          }
        ' < file.xml > results.xml

聽起來你只需要:

awk 'NR==FNR{nums[NR]=$0;next} sub(/<value>.*<\/value>/,"<value>"nums[i+1]"</value>"){i++}' file.txt file.xml

但鑒於您的問題中的小樣本XML輸入文件並且沒有關聯的TXT文件,很難猜測,因此我們沒有任何可測試的內容。

請記住這個:

  1. 每次在shell中編寫一個循環來操作文本時,你的方法都是錯誤的。 請參閱https://unix.stackexchange.com/questions/169716/why-is-using-a-shell-loop-to-process-text-considered-bad-practice
  2. shell是一個環境,用於操作文件和進程以及對工具進行調用。 用於操作文本的UNIX工具是awk。 閱讀Arnold Robbins撰寫的Effective Awk Programming,第4版。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM