使用Regex替换或追加文件中的行| Linux Shell脚本

时间:2022-05-08 05:53:16

I am trying to find the proper command to execute on a file that looks something like this: (ie .cshrc files)

我试图在一个看起来像这样的文件上找到正确的命令:(即.cshrc文件)

setenv BLAH foo

I need the command to replace the line where it detects the string BLAH and replace the entire line like such:

我需要命令来替换它检测到字符串BLAH的行并替换整行,如下所示:

setenv BLAH newfoo 

If BLAH doesn't exist in the file, then append it to the file.

如果文件中不存在BLAH,则将其附加到文件中。

I've played around with sed like such, but this does not achieve my goal.

我和sed这样玩过,但这并没有实现我的目标。

sed 's/^.*?BLAH.*/setenv BLAH newfoo/g' text.txt > text.tmp && mv text.tmp text.txt

I've also played with awk and also cant seem to get the command working exactly how i want it.

我也玩过awk并且似乎无法让命令正常工作我想要它。

awk -v s="setenv BLAH newfoo" '/^BLAH/{f=1;$0=s}7;END{if(!f)print s}' text.txt > text.tmp && mv text.tmp text.txt

Any ideas on how to achieve this would be awesome.

关于如何实现这一点的任何想法都会很棒。

UPDATE

I am trying to make this script work as expected.

我试图让这个脚本按预期工作。

script

ARG1="$1"
sed -i "/BLAH/s/^.*\$/setenv ${ENV_KEY} ${ENV_VAL}/g" file.txt
# If the BLAH keyword isnt there, append the file then.
grep -v -q "BLAH" file.txt && echo "setenv BLAH ${ARG1}" >> file.txt

file.txt (default)

setenv BLAH randomstring

setenv BLAH randomstring

usage of script

script.sh newvalue

file.txt (result)

setenv BLAH newvalue

setenv BLAH newvalue

Currently the script seems to be appending the file everytime. I'd also tried a few of the other recommendations but i cannot get them to accept the incoming arg1 value in the sed string.

目前,该脚本似乎每次都附加该文件。我还尝试了一些其他的建议,但我不能让他们接受sed字符串中的传入arg1值。

4 个解决方案

#1


5  

Intro

This could by done by this script:

这可以通过这个sed脚本完成:

sed  '/BLAH/{s/ \w+$/ newfoo/;h};${x;/BLAH/ba;x;s/$/\nsetenv BLAH newfoo/;x;:a;x}'

Explanation

sed -e '
    /^\(\|.*\W\)BLAH\(\W.*\|\)$/{  # lines matching word BLAH
      s/ \w\+$/ newfoo/; # replace last word by "newfoo"
      h;         # Store for not adding them at end of file 
    };
    ${           # On last line...
      x;         # Swap stored line with current line
      /BLAH/ba;  # if match, branch to label a:
      x;         # Swap back
      s/$/\nsetenv BLAH newfoo/; # Replace end of line with newline...
      x;         # Swap again
    :a;          # Label a:
      x          # Swap back
}'

You could use with in place edition switch:

您可以使用就地编辑开关:

sed -e'/BLAH/{h};${x;/BLAH/ba;x;s/$/\nsetenv BLAH newfoo/;x;:a;x}' -i text.txt

To be more accurate, search for delimited word BLAH:

为了更准确,搜索分隔的单词BLAH:

sed -e '
    /^\(.*\W\|\)BLAH\(\W.*\|\)$/{h}; # Store lines matching word BLAH
    ${           # On last line...
      x;         # Swap stored line with current line
      /./ba;  # if match, branch to label a:
      x;         # Swap back
      s/$/\nsetenv BLAH newfoo/; # Replace end of line with newline...
      x;         # Swap again
    :a;          # Label a:
      x          # Swap back
    }'  <(echo BLAH=foo;seq 1 4)
BLAH=foo
1
2
3
4

while

sed -e '
    /^\(.*\W\|\)BLAH\(\W.*\|\)$/{h}; # Store lines matching word BLAH
    ${           # On last line...
      x;         # Swap stored line with current line
      /./ba;  # if match, branch to label a:
      x;         # Swap back
      s/$/\nsetenv BLAH newfoo/; # Replace end of line with newline...
      x;         # Swap again
    :a;          # Label a:
      x          # Swap back
    }'  <(echo BLAHBLAH=foo;seq 1 4)
BLAHBLAH=foo
1
2
3
4
setenv BLAH newfoo

You may see that second BLAH was replaced by .. This could be done because if 1st was not found, swap space is empty. So if there is at least one char, this mean that 1st did occure.

您可能会看到第二个BLAH被替换为..这可以完成,因为如果未找到1st,则交换空间为空。因此,如果至少有一个字符,这意味着第一个确实发生了。

Clean and script

There is a way to make this more scriptable:

有一种方法可以使它更具脚本化:

sedcmd='/^\(.*\W\|\)%s\(\W.*\|\)$/{s/ \w\+$/ %s/;h};'
sedcmd+='${x;/./ba;x;s/$/\\nsetenv %s %s/;x;:a;x}'
varnam=BLAH
varcnt=foo
filnam=/tmp/file.txt
printf -v sedcmd "$sedcmd" ${varnam} ${varcnt} ${varnam} ${varcnt}
sed -e "$sedcmd" -i "$filnam"

You could remove -i switch on last line...

您可以在最后一行删除-i开关...

You could try this by running:

您可以通过运行来尝试:

sed -e "$sedcmd" <(echo setenv BLAH oldfoo;seq 1 4) 
setenv BLAH foo
1
2
3
4

sed -e "$sedcmd" <(echo setenv BLAHBLAH oldfoo;seq 1 4) 
setenv BLAHBLAH oldfoo
1
2
3
4
setenv BLAH foo

#2


1  

This awk command should work for both cases:

这个awk命令应该适用于这两种情况:

awk -v kw='BLAH' '$2 == kw{$3="newfoo"; seen=1} 1;
      END{if (!seen) print "setenv " kw " newfoo"}' file

You can pass ny other keyword to search using -v kw=... command line option.

您可以使用-v kw = ...命令行选项将ny其他关键字传递给搜索。

END block will execute only when given keyword is not found in the file.

只有在文件中找不到给定的关键字时,END块才会执行。

#3


1  

This might work for you (GNU sed):

这可能适合你(GNU sed):

sed '/blah/h;//s/foo/newfoo/;$!b;G;/blah/!s/.$/&setenv blah newfoo/;t;P;d' file

If blah found store that line in the hold space (HS) and substitute newfoo for foo. Print each line if not end-of-file. At end-of-file append the HS to the pattern space and check for blah. If not found append setenv blah newfoo and print otherwise print the last line and delete the remainder.

如果blah发现在保留空间(HS)中存储该行并用newfoo替换foo。如果不是文件结尾,则打印每一行。在文件结尾处将HS附加到模式空间并检查等等。如果没有找到附加setenv blah newfoo并打印否则打印最后一行并删除剩余部分。

#4


1  

I think you can make the sed a bit easier if you pass over it with a quick grep afterward and append the text if its still not found.

我认为你可以使sed更容易,如果你之后用快速grep传递它,并附加文本,如果它仍然没有找到。

E.g.

ENV_KEY=BLAH
ENV_VAL=foo
sed -i "/BLAH/s/^.*\$/setenv ${ENV_KEY} ${ENV_VAL}/g" text.tmp
! grep -q "${ENV_KEY}" text.tmp && echo "setenv ${ENV_KEY} ${ENV_VAL}" >> text.tmp

ENV_KEY = BLAH ENV_VAL = foo sed -i“/BLAH/s/^.*\$/setenv $ {ENV_KEY} $ {ENV_VAL} / g”text.tmp! grep -q“$ {ENV_KEY}”text.tmp && echo“setenv $ {ENV_KEY} $ {ENV_VAL}”>> text.tmp

This tells sed to search for the string BLAH, if it finds it then replace the entire line ^.*$. The -i option tells sed to update the file in place.

这告诉sed搜索字符串BLAH,如果找到它然后替换整行^。* $。 -i选项告诉sed更新文件。

#1


5  

Intro

This could by done by this script:

这可以通过这个sed脚本完成:

sed  '/BLAH/{s/ \w+$/ newfoo/;h};${x;/BLAH/ba;x;s/$/\nsetenv BLAH newfoo/;x;:a;x}'

Explanation

sed -e '
    /^\(\|.*\W\)BLAH\(\W.*\|\)$/{  # lines matching word BLAH
      s/ \w\+$/ newfoo/; # replace last word by "newfoo"
      h;         # Store for not adding them at end of file 
    };
    ${           # On last line...
      x;         # Swap stored line with current line
      /BLAH/ba;  # if match, branch to label a:
      x;         # Swap back
      s/$/\nsetenv BLAH newfoo/; # Replace end of line with newline...
      x;         # Swap again
    :a;          # Label a:
      x          # Swap back
}'

You could use with in place edition switch:

您可以使用就地编辑开关:

sed -e'/BLAH/{h};${x;/BLAH/ba;x;s/$/\nsetenv BLAH newfoo/;x;:a;x}' -i text.txt

To be more accurate, search for delimited word BLAH:

为了更准确,搜索分隔的单词BLAH:

sed -e '
    /^\(.*\W\|\)BLAH\(\W.*\|\)$/{h}; # Store lines matching word BLAH
    ${           # On last line...
      x;         # Swap stored line with current line
      /./ba;  # if match, branch to label a:
      x;         # Swap back
      s/$/\nsetenv BLAH newfoo/; # Replace end of line with newline...
      x;         # Swap again
    :a;          # Label a:
      x          # Swap back
    }'  <(echo BLAH=foo;seq 1 4)
BLAH=foo
1
2
3
4

while

sed -e '
    /^\(.*\W\|\)BLAH\(\W.*\|\)$/{h}; # Store lines matching word BLAH
    ${           # On last line...
      x;         # Swap stored line with current line
      /./ba;  # if match, branch to label a:
      x;         # Swap back
      s/$/\nsetenv BLAH newfoo/; # Replace end of line with newline...
      x;         # Swap again
    :a;          # Label a:
      x          # Swap back
    }'  <(echo BLAHBLAH=foo;seq 1 4)
BLAHBLAH=foo
1
2
3
4
setenv BLAH newfoo

You may see that second BLAH was replaced by .. This could be done because if 1st was not found, swap space is empty. So if there is at least one char, this mean that 1st did occure.

您可能会看到第二个BLAH被替换为..这可以完成,因为如果未找到1st,则交换空间为空。因此,如果至少有一个字符,这意味着第一个确实发生了。

Clean and script

There is a way to make this more scriptable:

有一种方法可以使它更具脚本化:

sedcmd='/^\(.*\W\|\)%s\(\W.*\|\)$/{s/ \w\+$/ %s/;h};'
sedcmd+='${x;/./ba;x;s/$/\\nsetenv %s %s/;x;:a;x}'
varnam=BLAH
varcnt=foo
filnam=/tmp/file.txt
printf -v sedcmd "$sedcmd" ${varnam} ${varcnt} ${varnam} ${varcnt}
sed -e "$sedcmd" -i "$filnam"

You could remove -i switch on last line...

您可以在最后一行删除-i开关...

You could try this by running:

您可以通过运行来尝试:

sed -e "$sedcmd" <(echo setenv BLAH oldfoo;seq 1 4) 
setenv BLAH foo
1
2
3
4

sed -e "$sedcmd" <(echo setenv BLAHBLAH oldfoo;seq 1 4) 
setenv BLAHBLAH oldfoo
1
2
3
4
setenv BLAH foo

#2


1  

This awk command should work for both cases:

这个awk命令应该适用于这两种情况:

awk -v kw='BLAH' '$2 == kw{$3="newfoo"; seen=1} 1;
      END{if (!seen) print "setenv " kw " newfoo"}' file

You can pass ny other keyword to search using -v kw=... command line option.

您可以使用-v kw = ...命令行选项将ny其他关键字传递给搜索。

END block will execute only when given keyword is not found in the file.

只有在文件中找不到给定的关键字时,END块才会执行。

#3


1  

This might work for you (GNU sed):

这可能适合你(GNU sed):

sed '/blah/h;//s/foo/newfoo/;$!b;G;/blah/!s/.$/&setenv blah newfoo/;t;P;d' file

If blah found store that line in the hold space (HS) and substitute newfoo for foo. Print each line if not end-of-file. At end-of-file append the HS to the pattern space and check for blah. If not found append setenv blah newfoo and print otherwise print the last line and delete the remainder.

如果blah发现在保留空间(HS)中存储该行并用newfoo替换foo。如果不是文件结尾,则打印每一行。在文件结尾处将HS附加到模式空间并检查等等。如果没有找到附加setenv blah newfoo并打印否则打印最后一行并删除剩余部分。

#4


1  

I think you can make the sed a bit easier if you pass over it with a quick grep afterward and append the text if its still not found.

我认为你可以使sed更容易,如果你之后用快速grep传递它,并附加文本,如果它仍然没有找到。

E.g.

ENV_KEY=BLAH
ENV_VAL=foo
sed -i "/BLAH/s/^.*\$/setenv ${ENV_KEY} ${ENV_VAL}/g" text.tmp
! grep -q "${ENV_KEY}" text.tmp && echo "setenv ${ENV_KEY} ${ENV_VAL}" >> text.tmp

ENV_KEY = BLAH ENV_VAL = foo sed -i“/BLAH/s/^.*\$/setenv $ {ENV_KEY} $ {ENV_VAL} / g”text.tmp! grep -q“$ {ENV_KEY}”text.tmp && echo“setenv $ {ENV_KEY} $ {ENV_VAL}”>> text.tmp

This tells sed to search for the string BLAH, if it finds it then replace the entire line ^.*$. The -i option tells sed to update the file in place.

这告诉sed搜索字符串BLAH,如果找到它然后替换整行^。* $。 -i选项告诉sed更新文件。