操作 ls 文本输出以添加文件名路径

操作 ls 文本输出以添加文件名路径

我有时会得到具有以下 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 部分。

相关内容