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 sed 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 sed 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更新文件。