awk 中可以删除字段吗?

问题描述 投票:0回答:11

这是

test.txt
:

0x01,0xDF,0x93,0x65,0xF8
0x01,0xB0,0x01,0x03,0x02,0x00,0x64,0x06,0x01,0xB0
0x01,0xB2,0x00,0x76

如果我跑步

awk -F, 'BEGIN{OFS=","}{$2="";print $0}' test.txt
结果是:

0x01,,0x93,0x65,0xF8
0x01,,0x01,0x03,0x02,0x00,0x64,0x06,0x01,0xB0
0x01,,0x00,0x76

$2 并没有被删除,只是变空了。 我希望,当打印 $0 时,结果是:

0x01,0x93,0x65,0xF8
0x01,0x01,0x03,0x02,0x00,0x64,0x06,0x01,0xB0
0x01,0x00,0x76
awk sed cut
11个回答
27
投票

所有现有的解决方案都很好,尽管这实际上是为

cut
量身定制的工作:

cut -d, -f 1,3- file

0x01,0x93,0x65,0xF8
0x01,0x01,0x03,0x02,0x00,0x64,0x06,0x01,0xB0
0x01,0x00,0x76

如果您想删除第三个字段,请使用:

cut -d, -f 1,2,4- file

要删除第四个字段,请使用:

cut -d, -f 1-3,5- file

10
投票

我相信最简单的方法是使用

sub
函数将第一次出现的连续
,,
(在将第二个字段设为 NULL 后创建)替换为单个
,
。但这假设您在字段值之间没有任何逗号。

awk 'BEGIN{FS=OFS=","}{$2="";sub(/,,/,",");print $0}' Input_file

第二个解决方案: 或者您可以使用

match
函数来捕获从第一个逗号到下一个逗号出现的正则表达式,并获取匹配字符串的前后行。

awk '
match($0,/,[^,]*,/){
  print substr($0,1,RSTART-1)","substr($0,RSTART+RLENGTH)
}' Input_file

6
投票

这有点粗暴,但这会将字段 2 之后的每个字段向下移动一个位置,然后进行更改

NF
,以便不存在不需要的字段:

$ awk -F, -v OFS=, '{ for (i = 2; i < NF; i++) $i = $(i+1); NF--; print }' test.txt
0x01,0x93,0x65,0xF8
0x01,0x01,0x03,0x02,0x00,0x64,0x06,0x01
0x01,0x00,0x76
$

使用 GNU Awk 4.1.3 和 BSD Awk 进行了测试(macOS Mojave 10.14.6 上的“

awk version 20070501
”——别问;这也让我很沮丧,但有时雇主不太善于前瞻性思考)。 设置
NF
在旧版本的 Awk 上可能有效,也可能无效 — 我有点惊讶它 有效,但作为一种改变,这个惊喜是令人愉快的。


3
投票

如果 Awk 不是绝对要求,并且输入确实像您的示例中一样微不足道,那么

sed
可能是一个更简单的解决方案。

sed 's/,[^,]*//' test.txt

如果您想删除第二个字段,这尤其优雅。 更通用的删除方法是,第 nth 字段需要您放入一个正则表达式,该正则表达式与第一个 n - 1 匹配,然后是第 nth,然后将其替换为第一个 n - 1.

所以对于 n = 4 你会有

sed 's/\([^,]*,[^,]*,[^,]*,\)[^,]*,/\1/' test.txt

或更一般地说,如果您的

sed
方言理解大括号来指定重复

sed 's/\(\([^,]*,\)\{3\}\)[^,]*,/\1/' test.txt

某些

sed
方言允许您使用
-r
-E
等选项来删除所有那些讨厌的反斜杠,但同样,这并不普遍支持或可移植。

如果不明显,

[^,]
匹配非(换行符或)逗号的单个字符;
\1
调用第一个括号匹配的文本(反向引用;
\2
调用第二个,依此类推)。

此外,这完全不适合转义或引用的字段(尽管我并不是说它不能完成)。 无论如何,每个逗号都充当字段分隔符。


2
投票

使用 GNU sed,您可以添加数字修饰符来替换第 n 个匹配的非逗号字符,后跟逗号:

sed -E 's/[^,]*,//2' file

2
投票

以无正则表达式的方式使用 awk,可以选择删除哪一行:

awk '{ col = 2; n = split($0,arr,","); line = ""; for (i = 1; i <= n; i++) line = line ( i == col ? "" : ( line == "" ? "" : ","  ) arr[i] ); print line }' test.txt

一步一步:

{
col = 2    # defines which column will be deleted
n = split($0,arr,",")    # each line is split into an array
                         # n is the number of elements in the array

line = ""     # this will be the new line

for (i = 1; i <= n; i++)   # roaming through all elements in the array
    line = line ( i == col ? "" : ( line == "" ? "" : "," ) arr[i] )
    # appends a comma (except if line is still empty)
    # and the current array element to the line (except when on the selected column)

print line    # prints line
}

1
投票

另一种解决方案:

您可以将输出通过管道传输到另一个 sed 并压缩分隔符。

$ awk -F, 'BEGIN{OFS=","}{$2=""}1 ' edward.txt  | sed 's/,,/,/g'
0x01,0x93,0x65,0xF8
0x01,0x01,0x03,0x02,0x00,0x64,0x06,0x01,0xB0
0x01,0x00,0x76
$

1
投票

评论@RavinderSingh13使用sub()函数的第一个解决方案:

awk 'BEGIN{FS=OFS=","}{$2="";sub(/,,/,",");print $0}' Input_file

gnu-awk
手册:https://www.gnu.org/software/gawk/manual/html_node/Changing-Fields.html

需要注意的是,对现有字段进行赋值会更改 $0 的值,但不会更改 NF 的值,即使将空字符串赋给字段也是如此。”(4.4 更改字段的内容)

因此,遵循 RavinderSingh13 的第一个解决方案,但在这种情况下不使用,

sub()
“该字段仍然存在;它只是有一个空值,由两个冒号分隔”:

awk 'BEGIN {FS=OFS=","} {$2="";print $0}' file 
0x01,,0x93,0x65,0xF8
0x01,,0x01,0x03,0x02,0x00,0x64,0x06,0x01,0xB0
0x01,,0x00,0x76

1
投票

我的解决方案:

awk -F, '
{
    regex = "^"$1","$2
    sub(regex, $1, $0);
    print $0;
}'

或一行代码:

awk -F, '{regex="^"$1","$2;sub(regex, $1, $0);print $0;}' test.txt

我发现 OFS="," 没有必要


0
投票

我会按照以下方式进行,让

file.txt
内容为:

0x01,0xDF,0x93,0x65,0xF8
0x01,0xB0,0x01,0x03,0x02,0x00,0x64,0x06,0x01,0xB0
0x01,0xB2,0x00,0x76

然后

awk 'BEGIN{FS=",";OFS=""}{for(i=2;i<=NF;i+=1){$i="," $i};$2="";print}' file.txt

输出

0x01,0x93,0x65,0xF8
0x01,0x01,0x03,0x02,0x00,0x64,0x06,0x01,0xB0
0x01,0x00,0x76

说明:我将

OFS
设置为空(空字符串),然后对于第二列和后续列,我在开始处添加
,
。最后我将现在的逗号和值设置为空。请记住,如果您希望删除第一列,则此解决方案需要返工。


0
投票

您可以通过管道传输到

tr -s ,

-s
--squeeze-repeats
:将最后一个指定数组中列出的重复字符的每个序列替换为该字符的一次出现

echo "0x01,0xDF,0x93,0x65,0xF8
0x01,0xB0,0x01,0x03,0x02,0x00,0x64,0x06,0x01,0xB0
0x01,0xB2,0x00,0x76" |
awk -F, 'BEGIN{OFS=","}{$2="";print $0}'|tr -s ,
# Out:
# 0x01,0x93,0x65,0xF8
# 0x01,0x01,0x03,0x02,0x00,0x64,0x06,0x01,0xB0
# 0x01,0x00,0x76
© www.soinside.com 2019 - 2024. All rights reserved.