我想使用 AWK 从以下输出中删除前 8 列:
ls -l
lrwxrwxrwx 1 user user 23 jul 27 00:04 file1.pdf
-rw-rw-r-- 1 user user 107 may 8 13:59 file 2 with spaces.mp3
lrwxrwxrwx 1 user user 11 jul 24 19:43 file3-with-hyphens.txt
lrwxrwxrwx 1 user user 11 jul 24 19:43 and_another_file4_with_underscores.md
-rw-rw-r-- 1 user user 107 may 8 13:59 file 5 with way more spaces than the rest.mp3
并将结果发送到文本文件。我可以使用可视块选择在 vim 中手动执行此操作,但我更希望使用脚本自动执行此操作。
环顾四周,我发现 这页面上,通过更改第 9 个示例的相关部分并根据需要多次将输出通过管道传输到自身,我能够获得所需的结果,但我觉得必须有更好的(更优雅和/或更紧凑)的方法来做到这一点,但无法找到它或想出我自己的。
我的最终代码如下:
awk '{for(i=1;i<=NF;i++)if(i!=x)f=f?f FS $i:$i;print f;f=""}' x=1 ~/file_folder_content.txt | awk '{for(i=1;i<=NF;i++)if(i!=x)f=f?f FS $i:$i;print f;f=""}' x=1 | ... | awk '{for(i=1;i<=NF;i++)if(i!=x)f=f?f FS $i:$i;print f;f=""}' x=1 >> ~/file_folder_content.txt
注 1:我预计该命令的实际输出ls
将比这大得多。
注 2:我尝试打印第 9 个字段,但由于某些文件名包含空格,因此只会打印文件名中的第一个单词。
答案1
这应该可以做你想做的事awk
:
ls -l | awk '$9~/./{for (i=1;i<9;i++){$i=""}; gsub(/^ +/,""); print}'
这是一个略有不同的方法perl
:
ls -l | perl -lane 'if ($F[7]=~/./) {s/.*$F[7]//; print}'
笔记:我不得不建议你仔细考虑一下你真正想要实现的目标,因为可能还有更好的方法。正如@五彩纸屑,只需打印文件名就可以更直接地完成ls -1
。
笔记:正如评论中正确指出的那样,此解决方案并不可靠。我想补充一点,没有解析ls
可以被认为是安全可靠的。
学习AWK:由于 OP 在评论中解释说这个问题是熟练掌握 AWK 的更广泛探索的一部分,因此我有一些建议。
答案2
这看起来像XY问题.ls -1
应该会打印您想要的内容。POSIX 要求使用此选项,因此您不太可能ls
不支持它。
但是如果你要解析结果,你不应该使用ls
一点也不。使用find
,最好配合-print0
行动。
所以ls
不是合适的工具。如果你坚持要解析裸ls
输出,那么awk
可能也不是合适的工具。理由:
- 您的列由空格分隔;有时有两个或三个连续的空格,这在每行中有所不同。因此,使用这种简单的分隔符,一行中的文件名可能从第 N 列开始,而另一行中的文件名则从第 (N+1) 列开始。
- 您可以告诉
awk
将多个空格视为一个分隔符(awk -F ' +'
),但这会使包含许多连续空格的文件名混乱。 - 因此,您需要一些逻辑来识别文件名在每一行中的起始位置。这是可以做到的(我相信这
awk
是图灵完备的),但我无法给您任何可行的解决方案。
ls -1
甚至不应该被解析的输出也ls -l
更糟糕。