我有一个输入csv文件,看起来像这样:
Name,Index,Location,ID,Message
Alexis,10,Punggol,4090b43,Production 4090b43
Scott,20,Bedok,bfb34d3,Prevent
Ronald,30,one-north,86defac,Difference 86defac
Cindy,40,Punggol,40d0ced,Central
Eric,50,one-north,aeff08d,Military aeff08d
David,60,Bedok,5d1152d,Study
我想使用awk
和gsub
编写一个 bash shell 脚本,将 ID 列下的 6-7 个字母数字字符长字符串替换为"xxxxx",输出在单独的.csv文件中。
现在我得到了:
#!/bin/bash
awk -F ',' -v OFS=',' '{gsub(/^([a-zA-Z0-9]){6,7}/g, "xxxxx", $4);}1' input.csv > output.csv
但是我从运行bash myscript.sh input.csv
中获得的输出没有任何意义。输出.csv文件如下所示:
Name,Index,Location,ID,Message
Alexis,10,Punggol,4xxxxx9xxxxxb43,Production 4090b43
Scott,20,Bedok,bfb34d3,Prevent
Ronald,30,one-north,86defac,Difference 86defac
Cindy,40,Punggol,4xxxxxdxxxxxced,Central
Eric,50,one-north,aeffxxxxx8d,Military aeff08d
David,60,Bedok,5d1152d,Study
但预期的输出 CSV 应如下所示:
Name,Index,Location,ID,Message
Alexis,10,Punggol,xxxxx,Production 4090b43
Scott,20,Bedok,xxxxx,Prevent
Ronald,30,one-north,xxxxx,Difference 86defac
Cindy,40,Punggol,xxxxx,Central
Eric,50,one-north,xxxxx,Military aeff08d
David,60,Bedok,xxxxx,Study
使用显示的示例,请尝试以下代码:
awk -F ',[[:space:]]+' -v OFS=',t' '
{
sub(/^([a-zA-Z0-9]){6,7}$/, "xxxxx", $4)
$1=$1
}
1
' Input_file | column -t -s $'t'
说明:将字段分隔符设置为逗号,空格,然后在此处将输出字段分隔符设置为逗号选项卡。然后用第 4 个字段中的xxxxx
替换字母数字的值从开始到结束(出现 6 到 7 次)。最后打印当前行。然后将awk
程序的输出发送到column
命令,以按照所示的OP示例进行制作。
编辑:如果您的Input_file现在仅按照编辑的样本,
分开,请尝试以下操作。
awk -F ',' -v OFS=',' '
{
sub(/^([a-zA-Z0-9]){6,7}$/, "xxxxx", $4)
}
1
' Input_file
注意:OP 从旧版本安装了最新版本的 awk,这些代码有所帮助。
您的答案的简短版本如下:
$ awk 'BEGIN{FS=OFS=","}(FNR>1){$4="xxxxxx"}1' file
这将用"xxxx"取代第4栏中的所有条目。
如果您只想更改第 4 列的前 6 到 7 个字符(如果只有 5 个字符,则不更改,有几种方法:
$ awk 'BEGIN{FS=OFS=","}(FNR>1)&&(length($4)>5){$4="xxxxxx" substr($4,8)}1' file
$ awk 'BEGIN{FS=OFS=","}(FNR>1)&&{sub(/.......?/,"xxxxxx",$4)}1' file
在这里,我们将 123456abcde 替换为 xxxxxxabcde
为什么脚本失败:
除了该方法错误的事实之外,我将尝试解释以下命令的作用:gsub(/([a-zA-Z0-9]){6,7}/g,"xxxxx",$4)
表示法/abc/g
是有效的 awk 语法,但它不会执行您希望它执行的操作。表示法/abc/
是 ERE 令牌(扩展正则表达式)。此时,g
表示法只不过是一个未定义的变量,默认为空字符串或零,具体取决于其用法。awk 现在将尝试通过首先执行/abc/
来执行操作/abc/g
,这意味着:如果我当前的记录 ($0
) 与正则表达式 "abc" 匹配,则返回1
否则返回0
。因此,它将/abc/g
转换为0g
这意味着将g
的内容连接到数字0
。为此,它将数字0
转换为字符串"0"
并将其与空字符串 g 连接起来。最后,您的gsub
命令等同于gsub("0","xxxxx",$4)
,并且意味着将所有零替换为"xxxxx"。
为什么你总是gsub("0","xxxxx",$4)
,从不gsub("1","xxxxx",$4)
.原因是您的初始正则表达式永远不会匹配完整记录/行中的任何内容 ($0
)。您的 reguar 表达式读取/^([a-zA-Z0-9]){6,7}/
,虽然有些行以 6 或 7 个字符开头,但您的 awk 可能无法识别扩展正则表达式表示法"{m,n}",这使其失败。如果您使用 gnu awk,则在使用-re-interval
时输出会有所不同,而在旧版本的 GNU awk 中默认情况下未启用。
我试图找到为什么你的代码会这样,为了简单起见,我只做了一个示例,只承认你使用过gsub
:
awk 'BEGIN{id="4090b43"}END{gsub(/^([a-zA-Z0-9]){6,7}/g, "xxxxx", id);print id}' emptyfile.txt
输出为
4xxxxx9xxxxxb43
删除第一个参数中的g
后
awk 'BEGIN{id="4090b43"}END{gsub(/^([a-zA-Z0-9]){6,7}/, "xxxxx", id);print id}' emptyfile.txt
输出为
xxxxx
因此,正则表达式后跟g
导致故障。我无法在 GNUAWK
手册中找到相关的段落,g
在/
之后应该做什么。
(在Gawk 4.2.1中测试)