我有时会得到具有以下 ls 输出格式的文件:
/etc/cron.d:
-rw-r--r-- 1 root root 128 May 15 2020 0hourly
-rw------- 1 root root 235 Dec 17 2020 sysstat
/etc/cron.daily:
-rw------- 1 root root 235 Dec 17 2020 sysstat
是否有机会使用普通的 gnu 工具甚至清除 bash 内部结构来操纵该内容:
-rw-r--r-- 1 root root 128 May 15 2020 /etc/cron.d/0hourly
-rw------- 1 root root 235 Dec 17 2020 /etc/cron.d/sysstat
-rw------- 1 root root 235 Dec 17 2020 /etc/cron.daily/sysstat
那太好了。
我的意思是最简单的方法是删除文件路径,如下所示:
cat <filename> | grep -v -E "^\/[a-z]"
但是就像我说的如何将这些路径移动到带有文件名的后续行?
给出的命令是:ls -lR /etc/cron* > <filename>
。
我对该输出没有影响,但我将 ls 执行的这些命令输出重定向到<filename>
传输给我的单独文件。
我喜欢做的是将其内容操纵到提到的第二个结果中。基本上获取第一行并应用文件第 2 行和第 3 行的路径,然后获取第 4 行并将其应用到第 5 行。然后将其配置为通用方法。
我认为使用 awk 应该可以。
答案1
如果您的文件或目录名都不包含空格,那么您可以使用任何 POSIX awk 执行以下操作:
$ awk '
NF==1 && sub(/:$/,"/") { dir=$0; next }
match($0,/[^[:space:]]+$/) { $0=substr($0,1,RSTART-1) dir substr($0,RSTART) }
{ print }
' file
-rw-r--r-- 1 root root 128 May 15 2020 /etc/cron.d/0hourly
-rw------- 1 root root 235 Dec 17 2020 /etc/cron.d/sysstat
-rw------- 1 root root 235 Dec 17 2020 /etc/cron.daily/sysstat
或者,如果您的文件/目录名称可以包含空格,但您的目录路径始终以 开头,/
并且您的ls
输出始终在文件名之前具有完全相同数量的字段(如示例所示),那么您可以执行以下操作:
$ awk '
/^\// && sub(/:$/,"/") { dir=$0; next }
match($0,/^([^[:space:]]+[[:space:]]+){8}/) { $0=substr($0,1,RLENGTH) dir substr($0,RLENGTH+1) }
{ print }
' file
但ls
并不总是使用这些字段生成输出(ls
日期/时间的输出取决于文件的期限和区域设置,并且用户 ID 可以包含空格,例如)以及每个文件行中的所有字符可以出现在目录名中,文件名可以以 结尾,:
因为文件和目录名可以包含除 YMMV 之外的任何字符,/
无论NUL
您想出什么来尝试区分行,然后找出文件名在每个文件行。另外,文件名可以包含换行符,这完全是另一个问题。
因此,没有可靠的方法来解析ls
它可能产生的每个可能的输出。如果您想这样做,那么您只需弄清楚您认为/希望哪种模式匹配足以满足您调用的任何上下文的需求ls
,然后基于此编写脚本。
由于其他一些工具正在ls
为您创建一个输出文件,然后必须进行解析,因此您应该尝试修复其他工具,因为众所周知,您不应该尝试解析ls
(请参阅http://mywiki.wooledge.org/ParsingLs和为什么*不*解析`ls`(以及该怎么做)?)所以这个工具会让你失败。
答案2
您还没有向我们展示您正在使用的命令或为什么会得到此输出,但如果目标是列出匹配的所有文件和目录/etc/cron*
,您可以改为使用find
:
find /etc/cron*
或者,如果您需要完整列表(GNU find
):
find /etc/cron* -ls
任何find
:
find /etc/cron* -exec ls -ld {} +
以下是我的 Arch Linux 上的示例输出:
$ ls /etc/cron*
/etc/cron.deny /etc/crontab /etc/crontab~ /etc/crontab.pacnew
/etc/cron.d:
0hourly
/etc/cron.daily:
/etc/cron.hourly:
0anacron
/etc/cron.monthly:
/etc/cron.weekly:
与find
:
$ find /etc/cron* -ls
262172 4 drwxr-xr-x 2 root root 4096 Jan 23 19:41 /etc/cron.d
263666 4 -rw-r--r-- 1 root root 128 Jan 14 14:59 /etc/cron.d/0hourly
262173 4 drwxr-xr-x 2 root root 4096 Sep 30 11:38 /etc/cron.daily
262618 4 -rw-r--r-- 1 root root 74 Jan 14 14:59 /etc/cron.deny
262174 4 drwxr-xr-x 2 root root 4096 Jan 23 19:41 /etc/cron.hourly
263665 4 -rwxr-xr-x 1 root root 843 Jan 14 14:59 /etc/cron.hourly/0anacron
262175 4 drwxr-xr-x 2 root root 4096 Jun 30 2016 /etc/cron.monthly
262632 0 -rw-r--r-- 1 root root 0 Oct 31 2017 /etc/crontab
262633 4 -rw-r--r-- 1 root root 49 Sep 22 2017 /etc/crontab~
272465 4 -rw-r--r-- 1 root root 119 Jan 14 14:59 /etc/crontab.pacnew
262176 4 drwxr-xr-x 2 root root 4096 Sep 30 11:38 /etc/cron.weekly
275802 4 -rwxr--r-- 1 root root 68 Sep 30 11:37 /etc/cron.weekly/clamscan.sh
答案3
解决方案与TXR 口齿不清。
让我们理所当然地认为您ls
从某个地方获得了此输出并且必须使用它;你无法回到原来的时间和机器并获取不同格式的信息。
$ txr lsdata.tl < lsdata
-rw-r--r-- 1 root root 128 May 15 2020 /etc/cron.d/0hourly
-rw------- 1 root root 235 Dec 17 2020 /etc/cron.d/sysstat
-rw------- 1 root root 235 Dec 17 2020 /etc/cron.daily/sysstat
哪里lsdata.tl
:
(let ((curdir ""))
(whilet ((line (get-line)))
(match-case line
(`@dir:` (set curdir dir))
(`@{metadata 39} @name` (put-line `@metadata @curdir/@name`)))))
这并不完美:它会被以 结尾的名称所欺骗:
。如果我们可以假设目录行区域始终是绝对路径,我们可以将其包含在匹配中:
(let ((curdir ""))
(whilet ((line (get-line)))
(match-case line
(`/@dir:` (set curdir dir))
(`@{metadata 39} @name` (put-line `@metadata /@curdir/@name`)))))
答案4
不完全确定你想要什么,但尝试这个命令:
$ ls -la | awk -v path=$PWD '{$NF=path"\/"$NF;print}' |sed 's| /| \t/|g'
如果对路径的对齐不感兴趣,您可以删除 sed 部分。