awk 中的 tr 命令更改列值
tr command in awk to change the column values
我在 shell 脚本中使用 awk 中的 TR 命令来屏蔽数据。当我在 awk 中使用 tr 命令时,下面的示例文件仅影响我的文件的第一行。当我在 while 循环中使用相同的方法并在其中调用 awk 命令时,它工作正常但需要很长时间才能完成。现在我的要求是我想在同一个文件(file.txt)中屏蔽许多列[例如:$1、$5、$9],这应该会影响整个文件而不是第一行,我想尽可能快地实现这一点屏蔽数据。请指教
猫file.txt
========
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs、degehek、lskjsjshsh
abcbchs,degehek
abcbchs、degehek、lskjsjshsh
输出
awk -F"," -v OFS="," '{ "echo \"""\" | tr \"a-c\" \"e-f\" | tr \"0-5\" \"6-9\"" | getline }7' file.txt
effffhs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs、degehek、lskjsjshsh
abcbchs,degehek
abcbchs、degehek、lskjsjshsh
预期输出
effffhs,degehek
effffhs,degehek
effffhs,degehek
effffhs,degehek
effffhs,degehek
effffhs、degehek、lskjsjshsh
effffhs,degehek
effffhs、degehek、lskjsjshsh
您找到的代码在每个输入行上运行一个外部 shell 命令管道。就像您发现的那样,这是执行您所要求的事情的一种非常低效的方式。 Awk 根本不是这项任务的理想选择。也许试试 Perl。
perl -F, -lane '$F[$_] =~ tr/a-c/e-f/ =~ tr/0-5/6-9/ for (0, 4, 8); print join(",", @F)' file
-F,
选项类似于 Awk,但 Perl 不会自动拆分输入行。使用 -a
时,它会拆分成一个名为 @F
的数组,而使用 -n
时,它会遍历所有输入行。 -l
可以方便地从每个输入行中删除换行符并在打印时添加一个换行符。
注意列是如何从零开始编号的,而不是像 Awk 中那样从一开始编号;所以 for
循环中的索引访问 @F
.
的第一个、第五个和第九个元素
您忘记在每次调用后 close()
命令。正确的写法是:
$ cat tst.awk
BEGIN { FS=OFS="," }
{
cmd="echo '" "' | tr 'a-c' 'e-f' | tr '0-5' '6-9'"
= ( (cmd | getline line) > 0 ? line : )
close(cmd)
print
}
$ awk -f tst.awk file
effffhs,degehek
effffhs,degehek
effffhs,degehek
effffhs,degehek
effffhs,degehek
effffhs,degehek,lskjsjshsh
effffhs,degehek
effffhs,degehek,lskjsjshsh
您也没有保护自己免受 getline 故障的影响,因此围绕 getline 调用增加了额外的复杂性,请参阅 http://awk.info/?tip/getline。
鉴于您的评论,这显示了如何同时修改多个字段(在本例中为 1、3 和 5):
$ cat tst.awk
BEGIN { FS=OFS="," }
{
cmd = "echo '" [=11=] "' | tr 'a-c' 'e-f' | tr '0-5' '6-9'"
new = ( (cmd | getline line) > 0 ? line : )
close(cmd)
split(new,tmp)
for (i in tmp) {
if (i ~ /^(1|3|5)$/) {
$i = tmp[i]
}
}
print
}
$ cat file
abc,abc,abc,abc,abc
abc,abc,abc,abc,abc,abc,abc
abc,abc,abc,abc,abc,abc
abc,abc,abc,abc
$ awk -f tst.awk file
eff,abc,eff,abc,eff
eff,abc,eff,abc,eff,abc,abc
eff,abc,eff,abc,eff,abc
eff,abc,eff,abc
处理输入数据中的引号:
$ cat tst.awk
BEGIN { FS=OFS="," }
{
gsub(/'/,SUBSEP)
cmd = "echo '" [=12=] "' | tr 'a-c' 'e-f' | tr '0-5' '6-9'"
new = ( (cmd | getline line) > 0 ? line : )
close(cmd)
split(new,tmp)
for (i in tmp) {
if (i ~ /^(1|3|5)$/) {
$i = tmp[i]
}
}
gsub(SUBSEP,"'")
print
}
$ cat file
a'c,abc,a"c,abc,abc
abc,a'c,abc,a"c,abc,abc,abc
abc,abc,abc,abc,abc,abc
abc,abc,abc,abc
$ awk -f tst.awk file
e'f,abc,e"f,abc,eff
eff,a'c,eff,a"c,eff,abc,abc
eff,abc,eff,abc,eff,abc
eff,abc,eff,abc
如果您没有任何保证不会出现在您的输入中的特定控制字符,您可以使用 [=15 末尾描述的技术创建一个不存在的字符串来代替上面的 SUBSEP =]
我在 shell 脚本中使用 awk 中的 TR 命令来屏蔽数据。当我在 awk 中使用 tr 命令时,下面的示例文件仅影响我的文件的第一行。当我在 while 循环中使用相同的方法并在其中调用 awk 命令时,它工作正常但需要很长时间才能完成。现在我的要求是我想在同一个文件(file.txt)中屏蔽许多列[例如:$1、$5、$9],这应该会影响整个文件而不是第一行,我想尽可能快地实现这一点屏蔽数据。请指教
猫file.txt
========
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs、degehek、lskjsjshsh
abcbchs,degehek
abcbchs、degehek、lskjsjshsh
输出
awk -F"," -v OFS="," '{ "echo \"""\" | tr \"a-c\" \"e-f\" | tr \"0-5\" \"6-9\"" | getline }7' file.txt
effffhs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs、degehek、lskjsjshsh
abcbchs,degehek
abcbchs、degehek、lskjsjshsh
预期输出
effffhs,degehek
effffhs,degehek
effffhs,degehek
effffhs,degehek
effffhs,degehek
effffhs、degehek、lskjsjshsh
effffhs,degehek
effffhs、degehek、lskjsjshsh
您找到的代码在每个输入行上运行一个外部 shell 命令管道。就像您发现的那样,这是执行您所要求的事情的一种非常低效的方式。 Awk 根本不是这项任务的理想选择。也许试试 Perl。
perl -F, -lane '$F[$_] =~ tr/a-c/e-f/ =~ tr/0-5/6-9/ for (0, 4, 8); print join(",", @F)' file
-F,
选项类似于 Awk,但 Perl 不会自动拆分输入行。使用 -a
时,它会拆分成一个名为 @F
的数组,而使用 -n
时,它会遍历所有输入行。 -l
可以方便地从每个输入行中删除换行符并在打印时添加一个换行符。
注意列是如何从零开始编号的,而不是像 Awk 中那样从一开始编号;所以 for
循环中的索引访问 @F
.
您忘记在每次调用后 close()
命令。正确的写法是:
$ cat tst.awk
BEGIN { FS=OFS="," }
{
cmd="echo '" "' | tr 'a-c' 'e-f' | tr '0-5' '6-9'"
= ( (cmd | getline line) > 0 ? line : )
close(cmd)
print
}
$ awk -f tst.awk file
effffhs,degehek
effffhs,degehek
effffhs,degehek
effffhs,degehek
effffhs,degehek
effffhs,degehek,lskjsjshsh
effffhs,degehek
effffhs,degehek,lskjsjshsh
您也没有保护自己免受 getline 故障的影响,因此围绕 getline 调用增加了额外的复杂性,请参阅 http://awk.info/?tip/getline。
鉴于您的评论,这显示了如何同时修改多个字段(在本例中为 1、3 和 5):
$ cat tst.awk
BEGIN { FS=OFS="," }
{
cmd = "echo '" [=11=] "' | tr 'a-c' 'e-f' | tr '0-5' '6-9'"
new = ( (cmd | getline line) > 0 ? line : )
close(cmd)
split(new,tmp)
for (i in tmp) {
if (i ~ /^(1|3|5)$/) {
$i = tmp[i]
}
}
print
}
$ cat file
abc,abc,abc,abc,abc
abc,abc,abc,abc,abc,abc,abc
abc,abc,abc,abc,abc,abc
abc,abc,abc,abc
$ awk -f tst.awk file
eff,abc,eff,abc,eff
eff,abc,eff,abc,eff,abc,abc
eff,abc,eff,abc,eff,abc
eff,abc,eff,abc
处理输入数据中的引号:
$ cat tst.awk
BEGIN { FS=OFS="," }
{
gsub(/'/,SUBSEP)
cmd = "echo '" [=12=] "' | tr 'a-c' 'e-f' | tr '0-5' '6-9'"
new = ( (cmd | getline line) > 0 ? line : )
close(cmd)
split(new,tmp)
for (i in tmp) {
if (i ~ /^(1|3|5)$/) {
$i = tmp[i]
}
}
gsub(SUBSEP,"'")
print
}
$ cat file
a'c,abc,a"c,abc,abc
abc,a'c,abc,a"c,abc,abc,abc
abc,abc,abc,abc,abc,abc
abc,abc,abc,abc
$ awk -f tst.awk file
e'f,abc,e"f,abc,eff
eff,a'c,eff,a"c,eff,abc,abc
eff,abc,eff,abc,eff,abc
eff,abc,eff,abc
如果您没有任何保证不会出现在您的输入中的特定控制字符,您可以使用 [=15 末尾描述的技术创建一个不存在的字符串来代替上面的 SUBSEP =]