如何根据文件中的字段值匹配模式并将其替换?

时间:2019-05-24 22:12:59

标签: regex bash scripting

我有以下格式的文本文件:

label1-label1/label2 label1
label3-label3/label4 label3
label5-label5/label6 label5

我要生成以下格式的输出:

label1/label2
label3/label4
label5/label6

我不能使用'-''/'作为分隔符,因为它们也是标签的一部分。

我尝试使用awksed命令从文件中提取$1$2,但无法弄清楚如何提供$2作为要从$1替换的原始模式。

我考虑过使用$2(label1)来匹配$1(label1-label1 / label2)中的模式并对其进行修整以得到结果,label1 / label2,但不知道如何做吧。

例如: Label1:美国,Label2:纽约

输入:-

United-States-United-States/New-York United-States

输出:-

United-States/New-York

3 个答案:

答案 0 :(得分:0)

这里是纯bash脚本的解决方案:

#!/bin/bash
while read -r line; do
    attachment="${line##* }"                  # get last part of line
    length="${#attachment}"                   # length of last part
    printf "%s\n" "${line:length+1:-length}"  # print line, shorten the start/end by last part
done < file.txt 

输入(file.txt)

label1-label1/label2 label1
label3-label3/label4 label3
label5-label5/label6 label5
United-States-United-States/New-York United-States
United/States/United/States/New-York United/States
United-States-United-States-New-York United-States
United$States$United$States$New$York United$States
United*States*United*States*New*York United*States

输出

label1/label2 
label3/label4 
label5/label6 
United-States/New-York 
United/States/New-York 
United-States-New-York 
United$States$New$York 
United*States*New*York 

答案 1 :(得分:0)

好主意也是如此...虽然可以使用awk拆分,但是使用while循环从文件中读取信息以及将第一个组合分开也很容易从label1label2<-end进行简单的参数扩展修剪,将所需数据分为beginning->'/'分隔它们的字符。届时,您只需要从1/2 length + 1中取出label1,然后将其与保存的label2组合成所需的字符串即可。

类似的东西:

while read -r label stuff; do   ## read combined label, ignore 2nd string stuff
    l1="${label%/*}"            ## isolate label1 (l1)
    l2="${label#*/}"            ## isolate label2 (l2)
    l1=${l1:$((${#l1}/2+1))}    ## take len/2+1 of l1
    echo "$l1/$l2"              ## put shortened l1 and l2 together
done < file

示例输入文件

使用输入文件和文件中显示的示例:

$ cat file
label1-label1/label2 label1
label3-label3/label4 label3
label5-label5/label6 label5
United-States-United-States/New-York United-States

使用/输出示例

只需在file所在目录的终端中选择并使用中间鼠标粘贴即可提供以下所需输出:

$ while read -r label stuff; do   ## read combined label, ignore 2nd string stuff
>     l1="${label%/*}"            ## isolate label1 (l1)
>     l2="${label#*/}"            ## isolate label2 (l2)
>     l1=${l1:$((${#l1}/2+1))}    ## take len/2+1 of l1
>     echo "$l1/$l2"              ## put shortened l1 and l2 together
> done < file
label1/label2
label3/label4
label5/label6
United-States/New-York

注意: UtLox是这里的第一个答案,因此无论出于何种考虑,都应给予优先权,这本质上是相同的方法,只是长度,除法的不同方法和加法发生

这里最简单的方法可能是,如果可以保证行的最后部分始终为label1。如果对您的文件而言这是有效的,那么您只需要单个参数扩展即可输出所需的结果,例如

while read -r label l1; do              ## read both parts of line
    echo "$l1/${label#*/}"              ## put l1 with trimmed label
done < file

使用/输出示例

$ while read -r label l1; do              ## read both parts of line
>     echo "$l1/${label#*/}"              ## put l1 with trimmed label
> done < file
label1/label2
label3/label4
label5/label6
United-States/New-York

如果每行的第二部分始终是您的label1(无需拆分'/'之前的内容),则这是一种更简单的方法

如果您还有其他问题,请告诉我。

答案 2 :(得分:0)

使用sed:

sed 's/^\(.*\)-\1\/\(.*\) \1$/\1\/\2/' file

此匹配项:

  • 行首
  • 跟随任何事情
  • 后跟连字符
  • 紧随其后的是
  • 后跟正斜杠
  • 紧随其后的可能是第二秒
  • 后跟一个空格
  • 紧随其后的是
  • 紧随行尾

并将其替换为:

  • 第一件事
  • 后跟斜杠
  • 之后是第二个

不匹配的行将保持不变。

如果输入格式错误,则不输出:

sed '/^\(.*\)-\1\/\(.*\) \1$/!d; s//\1\/\2/' file
  • 如果格式不正确则删除行
  • 否则执行替换