如何匹配“字段5到行尾”(例如,在awk中)

时间:2015-10-02 09:13:03

标签: awk gawk

我想漂亮地打印类似于find的脚本的输出,这些脚本将采用如下输入:

- 2015-10-02 19:45 102 /My Directory/some file.txt

并产生类似的东西:

-         102 /My Directory/some file.txt

换句话说:“f”(对于“文件”),文件大小(右对齐),然后是路径名(具有任意数量的空格)。

如果我能编写一个花费1美元,4美元和“从5美元到行尾的所有内容”的脚本,这在awk中很容易。

我尝试使用awk构造substr($ 0,index($ 0,$ 8)),我认为意味着“一切从字段$ 8开始到$ 0结尾”。

以这种方式使用index()作为linuxquestions.org上的解决方案提供,并在stackoverflow.com线程中被投票了29次。

然而,仔细观察,我发现如果起始字段恰好匹配字符串中的较早点,则index()不会达到此效果。例如,给定:

-rw-r--r-- 1 tbaker staff 3024 2015-10-01 14:39 calendar
-rw-r--r-- 1 tbaker staff 4062 2015-10-01 14:39 b
-rw-r--r-- 1 tbaker staff 2374 2015-10-01 14:39 now or later

Gawk(和awk)获得以下结果:

$ gawk '{ print index($0, $8) }' test.txt
49
15
49

换句话说,$ 8('b')的值匹配索引15而不是49(即,与大多数其他文件名一样)。

我的问题是如何指定“从字段X到字符串末尾的所有内容”。

我已经重写了这个问题,以便明确这一点。

3 个答案:

答案 0 :(得分:1)

在我看来你应该只使用" stat"命令而不是" ls",由于已经评论过的原因:

stat -c "f%15s %n" *

但你应该仔细检查你的" stat"操作;它显然可以是特定于shell的。

答案 1 :(得分:0)

有时建议使用内置的awk函数index()作为一种方法 打印“从字段5到字符串末尾”[1,2,3]。

在awk中,索引($ 0,$ 8)表示“第一个字符的索引” 字符串$ 0中的字段8“。相反,它表示”第一次出现的索引 字符串$ 0的字符串值8“。在许多情况下,第一个 发生将确实是第8场中的第一个字符,但这不是 上例中的情况。

有人指出,解析ls的输出通常是不好的 想法[4],部分原因是ls的实现在输出方面存在显着差异。 由于该说明的作者建议将find替换为某些用途的ls, 这是一个使用find的脚本:

find $@ -ls |
    sed -e 's/^ *//' -e 's/  */ /g' -e 's/ /|/2' -e 's/ /|/2' -e 's/ /|/4' -e 's/ /|/4' -e 's/ /|/6' |
    gawk -F'|' '{ $2 = substr($2, 1, 1) ; gsub(/^-/, "f", $2) }
                { printf("%s %15s %s\n", $2, $4, $6) }'

...产生所需的输出:

f            4639 /Users/foobar/uu/a
f            3024 /Users/foobar/uu/calendar
f            2374 /Users/foobar/uu/xpect

这种方法以递归方式遍历文件树。但是,find的版本之间当然也可能存在实现差异。

  1. http://www.linuxquestions.org/questions/linux-newbie-8/awk-print-field-to-end-and-character-count-179078/
  2. How to print third column to last column?
  3. Print Field 'N' to End of Line
  4. http://mywiki.wooledge.org/ParsingLs

答案 2 :(得分:0)

也许你正在寻找find -printf | awk的某些变体?

$ ls -l tmp
total 2
-rw-r--r-- 1 Ed None 7 Oct  2 14:35 bar
-rw-r--r-- 1 Ed None 2 Oct  2 14:35 foo
-rw-r--r-- 1 Ed None 0 May  3 09:55 foo bar

$ find tmp -type f -printf "f %s %p\n" | awk '{sub(/^[^ ]+ +[^ ]/,sprintf("%s %10d",$1,$2))}1'
f          7 tmp/bar
f          2 tmp/foo
f          0 tmp/foo bar

$ find tmp -type f -printf "%s %p\n" | awk '{sub(/^[^ ]+/,sprintf("f %10d",$1))}1'
f          7 tmp/bar
f          2 tmp/foo
f          0 tmp/foo bar

它不适用于包含换行符的文件名。