use*_*657 6 grep sed awk text-processing
这是一个文本处理问题。我有2个文件:
joeblogs
johnsmith
chriscomp
Run Code Online (Sandbox Code Playgroud)
12:00:00 (AAA) OUT: "string" joeblogs@hostname
12:00:00 (AAA) OUT: "string" joeblogs@hostname
12:00:00 (AAA) OUT: "string" johnsmith@hostname
12:00:00 (AAA) OUT: "string" joeblogs@hostname
12:00:00 (AAA) OUT: "string" chriscomp@hostname
Run Code Online (Sandbox Code Playgroud)
文件 1 包含出现在日志中的唯一用户名列表(文件 2)。
期望输出
12:00:00 (AAA) OUT: "string" USER1@hostname
12:00:00 (AAA) OUT: "string" USER1@hostname
12:00:00 (AAA) OUT: "string" USER2@hostname
12:00:00 (AAA) OUT: "string" USER1@hostname
12:00:00 (AAA) OUT: "string" USER3@hostname
Run Code Online (Sandbox Code Playgroud)
我想我不需要这两个文件。文件 1 是通过解析文件 2 的唯一用户名生成的。我的逻辑是获取我知道出现在文件 2 中的用户名列表,并循环遍历它,替换为sed
.
就像是:
for i in $(cat file1);do sed -e 's/$i/USER[X]';done
Run Code Online (Sandbox Code Playgroud)
当USER[X]
每个唯一的用户名递增。
但是我不能这样做。我什至不认为这种逻辑是合理的。我可以帮助实现所需的输出吗?awk
/ sed
/ grep
/bash
都欢迎。
正如您已经意识到“不需要 2 个文件”一样,请使用以下awk
解决方案一次性处理初始日志文件:
awk '{
u_name = substr($5, 1, index($5, "@"));
if (!(u_name in users)) users[u_name] = ++c;
sub(/^[^@]+/, "USER" users[u_name], $5)
}1' file.log
Run Code Online (Sandbox Code Playgroud)
输出:
12:00:00 (AAA) OUT: "string" USER1@hostname
12:00:00 (AAA) OUT: "string" USER1@hostname
12:00:00 (AAA) OUT: "string" USER2@hostname
12:00:00 (AAA) OUT: "string" USER1@hostname
12:00:00 (AAA) OUT: "string" USER3@hostname
Run Code Online (Sandbox Code Playgroud)
另一个 awk
awk '!($5 in a){a[$5]=++i}{sub("[^@]*","USER"a[$5],$5)}1' infile
Run Code Online (Sandbox Code Playgroud)
使用 bash 你可以这样做:
n=0
declare -A users=()
while IFS= read -r line; do
if [[ $line =~ ([^[:blank:]]+)@ ]]; then
user=${BASH_REMATCH[1]}
if [[ -z ${users[$user]} ]]; then
users[$user]=USER$((++n))
fi
line=${line/$user/${users[$user]}}
fi
echo "$line"
done < File2
Run Code Online (Sandbox Code Playgroud)
或 perl one-liner
perl -pe 's/(\S+)(?=@)/ $users{$1} ||= "USER".++$n /e' File2
Run Code Online (Sandbox Code Playgroud)