使用不同的字符串在多行上编辑文件

时间:2019-09-12 11:58:10

标签: bash

我正在研究一个脚本,该脚本将在所有行中查找文件,以查找下一行中是否在字符串A后跟字符串B。如果不正确,它将添加字符串C。

我设法做到了,但是我想在文件中的几个地方做到这一点。像这样

#!/bin/bash

match="match1"
match_following_line="following1"
insert='line_insert1'

file='words'
testfile='testfile'

#find linenumber for the first match
linenumber=$(awk -v myvar="$match" '$0~myvar {print NR}' $file)

#calculate linenumber for the comming line
linenumber2=$(( linenumber + 1 ))

#find string of that line
linecontent=$(sed -n "$linenumber2"p < $file)
echo $linecontent
#if it isn't match2 then add match2
if [ "$linecontent" != "$match_following_line" ]
then
    awk -v line="$linenumber" -v text="\n$insert" ' NR!=line{print} NR==line{print $0 text}' $file > $testfile
fi

文件words如下所示:

A
B
C
D
match1
After execusion the line before this line will become "line_insert1"
E

此文件testfile的输出为:

A
B
C
D
match1
line_insert1
After execusion the line before this line will become "line_insert1"
E

我尝试了几行:

match[0]='match1'
match_follower[0]='following1'
insert[0]='line_insert1'

match[1]='match2'
match_follower[1]='following2'
insert[1]='line_insert2'

match[2]='match3'
match_follower[2]='following3'
insert[2]='line_insert3'

file='1.csv'

for i in 0 1 2
do

#find linenumber for the first match
linenumber=$(awk -v myvar="${match[$i]}" '$0~myvar {print NR}' $file)
echo $linenumber
#calculate linenumber for the comming line
linenumber2=$(( linenumber + 1 ))

#find string of that line
linecontent=$(sed -n "$linenumber2"p < $file)
#if it isn't match_follower then add insert
if [ "$linecontent" != "${match_follower[$i]}" ]
then
        awk -v line="$linenumber" -v text="${insert[$i]}" ' NR!=line{print} NR==line{print $0 text}' $file > $file
fi
done

当我尝试对多个字符串执行此操作时,我不知道要做什么,因为awk会写入$ testfile并在每个循环中都覆盖该文件。有谁知道一个好的解决方案?

2 个答案:

答案 0 :(得分:2)

match[0]='match1'
match_follower[0]='following1'
insert[0]='line_insert1'

match[1]='match2'
match_follower[1]='following2'
insert[1]='line_insert2'

match[2]='match3'
match_follower[2]='following3'
insert[2]='line_insert3'

file='1.csv'

for i in 0 1 2
do

sed -E -i '/'"${match[$i]}"'/!b;n;/^'"${match_follower[$i]}"'|^'"${insert[$i]}"'/! i '"${insert[$i]}" ${file}

done

为了在sed中使用shell变量,必须关闭''并为变量打开""然后重新打开''等。这就是为什么要这样做的原因sed行中的qoute。

首先,用于sed的周期如下:

sed -E -i '/match1/!b;n;/^following1|^line_insert1/! i line_insert1' 1.csv

哪里

/match1/!找到NOT(!)包含match1的行,然后b阻止在当前行执行其余的sed脚本。如果不是这种情况,则sed脚本以n继续(;是命令块之间的分隔符)

n将下一行读入模式空间,因此sed脚本的其余部分将在下一行执行。

/^following1|^line_insert1/!确保脚本仅在当前模式空间(行)不是!^或{{1}开头(following1)的情况下插入行},line_insert1开关需要此正则表达式才能起作用。

-E这是实际行,它以给定文本i line_insert1为插入运算符插入新行。

i更改文件。


使用AWK,只需将sed行替换为此:

sed -i

awk -v v_match="${match[$i]}" -v v_follower="${match_follower[$i]}" -v v_insert="${insert[$i]}" ' {if (find_match == 1 && $0 !~ v_insert && $0 !~ v_follower ) { find_match=0 ; print v_insert } { find_match=0 ;print } } $0 ~ v_match { find_match=1 }' ${file} > tmp_file && mv tmp_file ${file} (如果行是$0 ~ v_match { find_match=1 },请将${match[$i]}变量设置为find_match

1如果{if (find_match == 1 && $0 !~ v_insert && $0 !~ v_follower ) {find_match=0 ; print v_insert } { find_match=0 ;print } }find_match并且行不是1${match_follower[$i]},则打印${insert[$i]},否则只打印当前行,设置{在两种情况下都是{1}}至${insert[$i]}

find_match,因为没有sed这样的临时文件功能需要临时文件(0)。

答案 1 :(得分:1)

您提前定位目标行位置的方法可能效果不佳 对于行号动态变化的情况,尤其是当 多行一一添加。

请尝试以下操作:

#/bin/bash

declare -a match=("match1" "match2" "match3")
declare -a match_follower=("following1" "following2" "following3")
declare -a insert=("line_insert1" "line_insert2" "line_insert3")

file="1.csv"

declare -a list
readarray -t list < "$file"

for i in "${!match[@]}"; do
    for j in "${!list[@]}"; do
        if [[ ${match[$i]} = ${list[$j]} ]] && [[ ${match_follower[$i]} != ${list[$(( $j + 1 ))]} ]]; then
            k=$(( j + 1 ))
            list=( "${list[@]:0:$k}" "${insert[$i]}" "${list[@]:$k}" )
            j=$k
        fi
    done
done

(IFS=$'\n'; echo "${list[*]}")

示例输入1.csv

A
B
C
D
match1
After execusion the line before this line will become "line_insert1"
E
F
G
match2
following2
After execusion the line before this line will NOT become "line_insert2"
H
I
J
match3
After execusion the line before this line will become "line_insert3"
K

输出

A
B
C
D
match1
line_insert1
After execusion the line before this line will become "line_insert1"
E
F
G
match2
following2
After execusion the line before this line will NOT become "line_insert2"
H
I
J
match3
line_insert3
After execusion the line before this line will become "line_insert3"
K
  • readarray将输入文件读入数组,设置数组元素 每行。 (需要bash 4.0或更高版本。)
  • 脚本遍历各行。如果一行与 ${match[$i]},下一行不同于${match_follower[$i]} 然后在下一个索引中插入元素${insert[$i]}