删除文件中匹配一个字符串但不匹配另一个字符串的行 - SED、BASH?

发布于 2024-11-18 02:30:09 字数 518 浏览 5 评论 0原文

我想删除文件中包含“test”一词的所有行,但如果该行包含“test@”,那么我不想删除它。

可能有一些时髦的方法可以用 sed 来做到这一点,但我很挣扎,我尝试使用 sed 编写一个 bash 循环,但这可能很愚蠢。

filetest=/tmp/filetest
filetest_tmp=/tmp/filetest.tmp<
line_num=0

while read line; do
        line_num=$(($line_num+1))
        if [[ $line == *rootsh* ]] && [[ $line != *root@* ]]
                then
                sed -e "${line_num}"'d' $filetest >> $filetest_tmp
        fi
done < $filetest
cp $syslog_tmp $filetest

正如你所知,我是这方面的新手:(

I want to remove all lines in a file which contain the word "test" but if that line contains "test@" then I do not want to delete it.

There is probably some funky way of doing this with sed but I am struggling, I tried to write a bash loop using sed but this is probably stupid.

filetest=/tmp/filetest
filetest_tmp=/tmp/filetest.tmp<
line_num=0

while read line; do
        line_num=$(($line_num+1))
        if [[ $line == *rootsh* ]] && [[ $line != *root@* ]]
                then
                sed -e "${line_num}"'d' $filetest >> $filetest_tmp
        fi
done < $filetest
cp $syslog_tmp $filetest

As you can tell, I'm a newb at this :(

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

浪菊怪哟 2024-11-25 02:30:09
sed -e '/test/{/test@/!d;}'

第一个模式匹配包含“test”的行;第二个模式删除行,除非它们匹配“test@”。

对数据文件进行测试:

aaaa
bbbtestbbb
ccctest@ccc
test!
dddd

输出:

aaaa
ccctest@ccc
dddd

这似乎满足您的要求。

您介意解释一下 sed 如何构造和使用该正则表达式吗?

sed 脚本的该行中有两个正则表达式:

  1. /test/ — 查找包含 test 的行。
  2. /test@/ — 查找包含 test@ 的行。

/test/{…} 表示法的意思是“当该行与 test 匹配时,在 中执行该操作。

/test@ /!d 表示“当该行与 test@ 不匹配时,将其删除”

。macOS 上的 sed 需要分号(可能还有其他 BSD-)。基于 Unix 的版本);对于 GNU 可以省略它sed,但由于它适用于两者(并且我最常在 macOS 上进行测试),因此保留它似乎是明智的做法,它标志着 !d 命令的结束。

sed -e '/test/{/test@/!d;}'

The first pattern matches the lines containing 'test'; the second pattern deletes lines unless they match 'test@'.

Tested on the data file:

aaaa
bbbtestbbb
ccctest@ccc
test!
dddd

Output:

aaaa
ccctest@ccc
dddd

That seems to meet your requirements.

Do you mind explaining how that regular expression is constructed and used by sed?

There are two regular expressions in that line of sed script:

  1. /test/ — looks for lines containing test.
  2. /test@/ — looks for lines containing test@.

The /test/{…} notation means "when the line matches test, do that actions in .

The /test@/!d means "when the line does not match test@, delete it".

The semicolon is needed with sed on macOS (and probably other BSD-based versions of Unix); it could be omitted with GNU sed, but since it works with both (and I test on macOS most often), it seems sensible to keep it. It marks the end of the !d command.

蓝颜夕 2024-11-25 02:30:09

使用 grep

grep -v 'test[^@]' infile

通常 grep 打印匹配的行,但 -v 告诉它打印不匹配的行。

正则表达式匹配任何出现的“test”,后跟除“@”之外的任何内容。如果您不必期望在行尾出现“test”,那么这很好。如果是这种情况,请使用

grep -E -v 'test([^@]|$)'

我认为不值得深入研究为什么您的解决方案不起作用,因为它在很多方面都被破坏了。

Use grep:

grep -v 'test[^@]' infile

Usually grep prints matching lines but -v tells it to print non-matching lines.

The regular expression matches any occurance of "test" that is followed by anything but a '@'. This is fine if you don't have to expect "test" coming up at the end of a line. If that is the case, use

grep -E -v 'test([^@]|$)'

I don't think it is worth going into why your solution does not work, because it is broken in so many ways.

孤凫 2024-11-25 02:30:09

如果您稍微翻转一下问题,它就会变成:

如何从文件中过滤出包含字符串“test@”或不包含字符串“test”的所有行。

例如,这可以在 awk 中完成,如下所示:

awk '!/foo/ || /foo@/' testfile

乔纳森的答案也有效,我只是想给你一个替代版本。

If you flip your question around a bit, it becomes:

How do I filter out all lines from a file that either contains the string 'test@' or does not contain the string 'test'.

This can for example be done in awk like this:

awk '!/foo/ || /foo@/' testfile

Jonathan's answer also works, I just wanted to give you an alternate version.

蓝天白云 2024-11-25 02:30:09

如果您使用ed,则不需要 tmp 文件!

# cf. http://wiki.bash-hackers.org/howto/edit-ed
cat <<-'EOF' | ed -s file
H
,g/test$/d
,g/test[^@]/d
wq
EOF

There is no need for a tmp file if you use ed!

# cf. http://wiki.bash-hackers.org/howto/edit-ed
cat <<-'EOF' | ed -s file
H
,g/test$/d
,g/test[^@]/d
wq
EOF
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文