打印 awk 中的其余字段
Posted
技术标签:
【中文标题】打印 awk 中的其余字段【英文标题】:Print rest of the fields in awk 【发布时间】:2013-08-29 17:33:06 【问题描述】:假设我们有这个数据文件。
john 32 maketing executive
jack 41 chief technical officer
jim 27 developer
dela 33 assistant risk management officer
我想使用awk
打印
john maketing executive
jack chief technical officer
jim developer
dela assistant risk management officer
我知道可以使用for
来完成。
awk 'printf $1; for(i=3;i<=NF;i++)printf " %s", $i printf "\n"' < file
问题是它很长而且看起来很复杂。
是否有任何其他简短的方法可以打印其余字段。
【问题讨论】:
一个简单的技巧是将 $2 设置为 "",然后打印 $0(所有字段)——尽管这会给你一个空字段的额外分隔符。 3 年后,你帮助了我。但是您应该将“将要跳过的字段设置为空白:
awk '$2 = ""; print $0;' < file_name
来源:Using awk to print all columns from the nth to the last
【讨论】:
不清理多余的空间,并使用可以用简单的1
替换的不需要的print $0
@Jotne 当我使用1
代替print $0
时,我没有从awk 获得任何输出。你确定它们是等价的吗?
@Alex 移除 print $0
并在关闭
之后放置 1
。【参考方案2】:
你可以像这样使用简单的 awk:
awk '$2=""1' file
然而,这会在你的输出中有一个额外的 OFS,这个 awk 可以避免
awk 'sub($2 OFS, "")1' file
或者使用这个 tr 和 cut 组合:
在 Linux 上:
tr -s ' ' < file | cut -d ' ' -f1,f3-
在 OSX 上:
tr -s ' ' < file | cut -d ' ' -f1 -f3-
【讨论】:
这应该是cut -d' ' -f1,3-
。
@AdrianFrühwirth:谢谢,但 cut -f1,3-
不可移植,我的 OSX 不支持。
您不应该使用awk 'sub($2 OFS, "")1'
,因为$2 中的相同文本可能位于$1 的末尾,和/或$2 可能包含RE 元字符,因此您很有可能会删除那个错误的字符串。
@anubhava - 不,在另一个字符串中查找字符串而不是 RE 的唯一 awk 函数是 index()。
@anubhava - 正确,没有简单的方法,但请参阅我的答案以获得可靠的方法。【参考方案3】:
这会删除文件 #2 并清理多余的空间。
awk '$2="";sub(" "," ")1' file
【讨论】:
额外的1
在这里做什么?
@shiplu.mokadd.im 1
的计算结果为 true,它会启动默认块 ( print $0
)。
不清理任何东西,而是像所有现有字段的重写一样 - 它将IFS
(连续一个或多个)替换为单个OFS
。例如。这是实现“规范化空间”过滤器的一种方法:awk '$1=$11'
【参考方案4】:
另一种方法是只使用 sed 替换第一个数字和空格匹配:
sed 's|[0-9]\+\s\+||' file
【讨论】:
【参考方案5】:在使用默认 FS 时可靠地使用 GNU awk for gensub():
$ gawk -v delNr=2 '$0=gensub("^([[:space:]]*([^[:space:]]+[[:space:]]+)"delNr-1")[^[:space:]]+[[:space:]]*","\\1","")1' file
john maketing executive
jack chief technical officer
jim developer
dela assistant risk management officer
对于其他 awk,您需要使用 match() 和 substr() 而不是 gensub()。请注意,上面的变量 delNr 告诉 awk 您要删除哪个字段:
$ gawk -v delNr=3 '$0=gensub("^([[:space:]]*([^[:space:]]+[[:space:]]+)"delNr-1")[^[:space:]]+[[:space:]]*","\\1","")1' file
john 32 executive
jack 41 technical officer
jim 27
dela 33 risk management officer
不要这样做:
awk 'sub($2 OFS, "")1'
因为 $2 中的相同文本可能位于 $1 的末尾,并且/或者 $2 可能包含 RE 元字符,因此您很有可能会以这种方式删除错误的字符串。
不要这样做:
awk '$2=""1' file
因为它添加了一个 FS,并将字段之间的所有其他连续空白压缩成一个单独的空白字符。
不要这样做:
awk '$2="";sub(" "," ")1' file
因为它有上面提到的空间压缩问题,并且依赖于单个空白的硬编码 FS(虽然是默认的,所以可能不是那么糟糕),但更重要的是,如果在 $1 之前有空格,它会删除其中一个那些而不是它在 $1 和 $2 之间添加的空间。
最后值得一提的是,在 gawk 的最新版本中,有一个名为 patsplit() 的新函数,它的工作方式与 split() 类似,但是除了创建字段数组之外,它还创建了一个空格数组田野。这意味着您可以在数组中操作字段和 then 之间的空格,因此如果您操作字段,您不必担心 awk 使用 OFS 重新编译记录。然后你只需要从数组中打印你想要的字段。有关更多信息,请参阅http://www.gnu.org/software/gawk/manual/gawk.html#String-Functions 中的 patsplit()。
【讨论】:
看到这些复杂性,人们想知道 awk 是否确实是完成这项工作的最佳工具。例如如果字段由管道或逗号分隔,则需要重写整个 awk 代码。 取决于您的输入。如果字段之间有单个字符,那么cut
会更好。如果您还有其他东西,那么 gawk+gensub() 或 sed(在语法上非常相似)可能是最好的选择。在尝试描述多字符 RE 的否定时,这两者都可能遇到问题,因此您需要查看 gawk+patsplit() 或 gawk+FPAT。不幸的是,没有灵丹妙药。
很好的答案我希望我能 +2 你。一个问题是代码比for
循环解决方案长得多。 f
@shiplu.mokadd.im - 正确,但它保留了原始空白,而您发布的 for 循环不会产生您指定的输出。顺便说一句,你发布的那个 for 循环 - 永远不要将 printf 与输入数据一起使用,例如printf $1
因为如果您的输入数据包含 printf 格式化字符(例如 %
),那将会非常失败。始终使用printf "%s",$1
代替打印输入数据。同样要打印换行符只是print ""
,不需要printf "\n"
。【参考方案6】:
使用不需要gawk
或任何状态突变的awk
的方法:
awk 'print $1 " " substr($0, index($0, $3));' datafile
UPD
更长一点的解决方案,但在 $1 或 $2 包含 $3 时会站得住脚:
awk 'print $1 " " substr($0, length($1 $2) + 1);' data
如果您有自定义字段分隔符,甚至更强大:
awk 'print $1 " " substr($0, length($1 FS $2 FS) + 1);' data
【讨论】:
【参考方案7】:不要使用改变 $n。如果您想保留某个部分的更多空间,它会减少到一个。
【讨论】:
以上是关于打印 awk 中的其余字段的主要内容,如果未能解决你的问题,请参考以下文章