如何在awk中保留字段之间的原始空白?

如何在awk中保留字段之间的原始空白?,awk,Awk,当使用awk处理输入时,有时我想编辑其中一个字段,而不涉及其他任何内容。考虑这一点: $ ls -l | awk 1 total 88 -rw-r--r-- 1 jack jack 8 Jun 19 2013 qunit-1.11.0.css -rw-r--r-- 1 jack jack 56908 Jun 19 2013 qunit-1.11.0.js -rw-r--r-- 1 jack jack 4306 Dec 29 09:16 test1.html -rw-r--r-- 1

当使用
awk
处理输入时,有时我想编辑其中一个字段,而不涉及其他任何内容。考虑这一点:

$ ls -l | awk 1
total 88
-rw-r--r-- 1 jack jack     8 Jun 19  2013 qunit-1.11.0.css
-rw-r--r-- 1 jack jack 56908 Jun 19  2013 qunit-1.11.0.js
-rw-r--r-- 1 jack jack  4306 Dec 29 09:16 test1.html
-rw-r--r-- 1 jack jack  5476 Dec  7 08:09 test1.js
如果我不编辑任何字段(
$1
$2
,…),所有内容都会保持原样。但如果我只想保留第一个字段的前3个字符:

$ ls -l | awk '{$1 = substr($1, 1, 3) } 1'
tot 88
-rw 1 jack jack 8 Jun 19 2013 qunit-1.11.0.css
-rw 1 jack jack 56908 Jun 19 2013 qunit-1.11.0.js
-rw 1 jack jack 4306 Dec 29 09:16 test1.html
-rw 1 jack jack 5476 Dec 7 08:09 test1.js
所有字段之间的原始空白被替换为一个简单的空格

有没有办法保留字段之间的原始空白

更新

在本示例中,编辑前4个字段相对容易。但是,如果我只想保留
$5
的第一个字母以获得此输出,该怎么办:

-rw-r--r-- 1 jack jack     8 J 19  2013 qunit-1.11.0.css
-rw-r--r-- 1 jack jack 56908 J 19  2013 qunit-1.11.0.js
-rw-r--r-- 1 jack jack  4306 D 29 09:16 test1.html
-rw-r--r-- 1 jack jack  5476 D  7 08:09 test1.js

可以通过编辑
$0
而不是单个字段(
$1
$2
,…)来保留原始空白,例如:

$ ls -l | awk '{$0 = substr($1, 1, 3) substr($0, length($1) + 1)} 1'
tot 88
-rw 1 jack jack     8 Jun 19  2013 qunit-1.11.0.css
-rw 1 jack jack 56908 Jun 19  2013 qunit-1.11.0.js
-rw 1 jack jack  4306 Dec 29 09:16 test1.html
-rw 1 jack jack  5476 Dec  7 08:09 test1.js
这在编辑第一列时相对容易,但在编辑其他列时会很麻烦(
$2
,…,
$4
),并且在空格宽度不固定的字段后会出现故障(
$5
,在本例中甚至更高)

更新

根据的答案,这里有一种方法可以保留第6个字段(月份)的前2个字符:

{
n=拆分($0,f,“,9月)
f[6]=substr(f[6],1,2)
行=九月[0]

对于(i=1;i如果要保留空白,也可以尝试使用
split
函数。 在Gnu Awk版本4中,
split
函数接受4个参数,其中后者是字段之间的分隔符

echo "a  2   4  6" | gawk ' {
 n=split($0,a," ",b)
 a[3]=7
 line=b[0]
 for (i=1;i<=n; i++)
     line=(line a[i] b[i])
 print line
}' 

我知道这是一个老问题,但我认为必须有更好的答案。这个答案是为那些在搜索时偶然发现这个问题的人提供的。当我在网上环顾四周时,我不得不说,我有最好的答案,这就是我最初使用的答案

但这是我的解决方案。使用。它可以设置一个正则表达式来说明字段应该是什么。在这种情况下,我是说字段应该以零个或多个空白字符开始,并基本上以除空白字符以外的任何其他字符结束。如果您在理解
POSIX
括号表达式时遇到问题,它是一个链接

 FPAT = "([[:space:]]*[[:alnum:][:punct:][:digit:]]+)";
另外,将输出字段更改为
OFS=“”;
分隔符,因为一旦对行进行了操作,如果不更改OFS的默认值,则输出将添加额外的空格作为分隔符

我用同样的例子来测试

$ cat example-output.txt
-rw-r--r-- 1 jack jack     8 Jun 19  2013 qunit-1.11.0.css
-rw-r--r-- 1 jack jack 56908 Jun 19  2013 qunit-1.11.0.js
-rw-r--r-- 1 jack jack  4306 Dec 29 09:16 test1.html
-rw-r--r-- 1 jack jack  5476 Dec  7 08:09 test1.js
请记住。字段现在有前导空格。因此,如果该字段需要替换为其他字段,您可以这样做

len = length($1); 
$1 = sprintf("%"(len)"s", "-42-");

最简单的解决方案是确保在每个空间上进行字段拆分。这是通过设置字段分隔符来实现的
[]

$ awk -F '[ ]' '{$1=substr($1,1,3)}1' infile

-rw 1 jack jack     8 Jun 19  2013 qunit-1.11.0.css
-rw 1 jack jack 56908 Jun 19  2013 qunit-1.11.0.js
-rw 1 jack jack  4306 Dec 29 09:16 test1.html
-rw 1 jack jack  5476 Dec  7 08:09 test1.js

默认情况下,awk将在任何重复的空格(制表符和空格,类似于
[\t]+
)上拆分。手册说明:

在FS是单个空格的特殊情况下,字段由空格和/或制表符和/或换行符分隔

这将在输出中将空格、制表符和换行符的运行折叠为一个OFS值。如果OFS也是一个空格(也是默认值),则每次运行空格时只打印一个空格

但是可以告诉awk使用只匹配一个字符的正则表达式只选择一个空格作为字段分隔符:
[]

请注意,这将更改字段的字段数。每个空格将开始一个新字段。因此,请注意您提供的数据的结果:

$ awk -F '[ ]' '{print($4,$5,$6)}' infile
jack
jack 56908 Jun
jack  4306
jack  5476

在这个特定的例子中,第一个字段前面没有空格,后面只有一个空格,这就是它工作正常的原因。

对于GNU awk,我建议使用
if(match($0,“^([^\t]+)[\t]+([^\t]+)[\t]+([^\t]+”,fields)){…
之类的方法来找出字段的位置。然后可以使用
字段[2,“start”]
字段[2,“开始”]+字段[2,“长度”]-1
,例如,获取第二个字段的开始和结束的索引。您可以将
[:alnum:][:punch:][:digit:][:digit:][]替换为
[^[:space:][
除了更加简洁之外,解决方案将更加健壮。idk
-42-
的内容是什么,但如果您只是试图在字段宽度中显示某个内容,它将被写为
$1=sprintf(“%*s”,len,“-42-”
,而不是
$1=sprintf(“%“(len)”s“,“-42-”)
。显然,当使用默认FS以外的其他解决方案时,整个解决方案都会崩溃,因此是首选。这是正确的答案,也是第4个arg to
split()的主要原因引入了
。在FS可以是任何regexp的一般情况下,任何其他内容都会变得非常复杂,而不仅仅是默认的空白或任何其他可以在括号表达式中求反的内容。
len = length($1); 
$1 = sprintf("%"(len)"s", "-42-");
$ awk 'BEGIN { FPAT = "([[:space:]]*[[:alnum:][:punct:][:digit:]]+)"; OFS = ""; } { if(NR==1){ len = length($1); $1 = sprintf("%"(len)"s", "-42-"); } print $0; }' example-output.txt
      -42- 1 jack jack     8 Jun 19  2013 qunit-1.11.0.css
-rw-r--r-- 1 jack jack 56908 Jun 19  2013 qunit-1.11.0.js
-rw-r--r-- 1 jack jack  4306 Dec 29 09:16 test1.html
-rw-r--r-- 1 jack jack  5476 Dec  7 08:09 test1.js
$ awk -F '[ ]' '{$1=substr($1,1,3)}1' infile

-rw 1 jack jack     8 Jun 19  2013 qunit-1.11.0.css
-rw 1 jack jack 56908 Jun 19  2013 qunit-1.11.0.js
-rw 1 jack jack  4306 Dec 29 09:16 test1.html
-rw 1 jack jack  5476 Dec  7 08:09 test1.js
$ awk -F '[ ]' '{print($4,$5,$6)}' infile
jack
jack 56908 Jun
jack  4306
jack  5476