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

时间:2015-11-10 20:22:09

标签: regex linux shell awk sed

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

setenv BLAH foo

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

setenv BLAH newfoo 

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

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

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

我也玩过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

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

更新

我正在努力使这个脚本按预期工作。

脚本

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(默认)

setenv BLAH randomstring

脚本的用法

script.sh newvalue

file.txt(result)

setenv BLAH newvalue

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

4 个答案:

答案 0 :(得分:5)

简介

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

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

解释

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
}'

您可以使用 in place edition 开关:

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

为了更准确,请搜索分隔的单词 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

,而

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

您可能会看到第二个BLAH.取代。这可以完成,因为如果找不到1st,则交换空间为空。因此,如果至少有一个字符,这意味着第一个出现了。

清理并编写脚本

有一种方法可以使这个可编写脚本

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"

你可以删除最后一行的-i开关......

你可以试试这个:

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

答案 1 :(得分:1)

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

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

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

只有在文件中找不到给定的关键字时,

END块才会执行。

答案 2 :(得分:1)

我认为如果你以后快速sed传递grep可以使ENV_KEY=BLAH更容易一些,如果仍未找到它,则附加文本。

E.g。

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
sed

这告诉^.*$搜索字符串BLAH,如果找到它,则替换整行-ised选项告诉B2:C11更新文件。

答案 3 :(得分:1)

这可能适合你(GNU sed):

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

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