使用AWK打印字段$2,然后是字段$1

54

这里是输入(示例):

name1@gmail.com|com.emailclient.account
name2@msn.com|com.socialsite.auth.account

我想要实现这个:

Emailclient name1@gmail.com
Socialsite name2@msn.com

如果我像这样使用 AWK:

cat foo | awk 'BEGIN{FS="|"} {print $2 " " $1}'

它通过将字段1覆盖在字段2的顶部而混乱了输出。

有什么提示/建议吗?谢谢。

4个回答

90

除了DOS行尾问题之外,还有一些一般性的提示:

cat是用于连接文件的命令,它不是唯一可以读取文件的工具!如果一个命令不能读取文件,则可以使用重定向,例如command < file

您可以使用-F选项设置字段分隔符,因此可以将:

cat foo | awk 'BEGIN{FS="|"} {print $2 " " $1}' 

尝试:

awk -F'|' '{print $2" "$1}' foo 

这将输出:

com.emailclient.account name1@gmail.com
com.socialsite.auth.accoun name2@msn.com
为了获得所需的输出,您可以采取各种方法。我可能会使用split()函数来分割第二个字段:
awk -F'|' '{split($2,a,".");print a[2]" "$1}' file
emailclient name1@gmail.com
socialsite name2@msn.com

最后,将第一个字符转换为大写字母在awk中有点麻烦,因为它没有一个很好的内置的ucfirst()函数:

awk -F'|' '{split($2,a,".");print toupper(substr(a[2],1,1)) substr(a[2],2),$1}' file
Emailclient name1@gmail.com
Socialsite name2@msn.com

如果你希望更加简洁(尽管你会失去一些子过程),可以这样做:

awk -F'|' '{split($2,a,".");print a[2]" "$1}' file | sed 's/^./\U&/'
Emailclient name1@gmail.com
Socialsite name2@msn.com

5
也许您的文件包含CRLF终止符,即每行后面跟着 \r\n。 awk 认为 $2 实际上是 $2\r,其中 \r 意味着回到行首。 {print $2\r$1} 将先打印 $2,然后返回开头,再打印 $1。因此,字段 2 被字段 1 覆盖。

欢迎来到Stack Overflow,SleepyProgrammer!如果可以的话,我建议您添加更多细节。这篇文章看起来像是一条评论,可能会被删除... - Badacadabra
非常感谢这个提示,当只有一列时就会出现这种情况,所以我只想添加另一列,但是$0(或$1)返回一个以\r结尾的字符串,导致“覆盖”初始列的意外行为。 - Oleg Afanasyev

3

使用点(.)或管道符(|)作为字段分隔符:

awk -v FS='[.|]' '{
    printf "%s%s %s.%s\n", toupper(substr($4,1,1)), substr($4,2), $1, $2
}' << END
name1@gmail.com|com.emailclient.account
name2@msn.com|com.socialsite.auth.account
END

提供:

Emailclient name1@gmail.com
Socialsite name2@msn.com

2
这是我的最初想法,但对于.co.uk.cam.ac.uk等等就会变得混乱。 - Chris Seymour

2

awk很好用。我猜文件来自Windows系统,行末有CR(^m ascii 0x0d)。

这会导致光标在$2之后回到行首。

使用dos2unix或vi与:se ff=unix来去除CRs。


每行都以0x0d0a结尾,这是您的意思吗?剪切这些十六进制值可以解决问题吗?谢谢。 - Sazzy
0a 是没问题的,只需去掉 0d 即可。 - parkydr
谢谢!将以下内容添加到管道中解决了问题:| sed 's/\x0d//g' | - Sazzy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接