从ls输出中提取文件名和修改时间

3
我有一个目录里的一组文件。我想从ls输出中提取仅包含文件名而不带绝对路径和修改时间戳的信息。
/apps/dir/file1.txt               
/apps/dir/file2.txt

现在从ls输出中提取出文件名和时间戳字段。

ls -ltr /apps/dir | awk '{print $6 $7 $8 $9}'

Sep  25  2013 /apps/dir/file1.txt  
Dec  20  2013 /apps/dir/file2.txt  
Dec  20  2013 /apps/dir/file3.txt

虽然我想要它像这样:
Sep 25  2013 file1     
Dec 20  2013 file2  
Dec 20  2013 file3

一种解决方法是进入该目录并从那里运行命令,但是否有可能不用cd而实现解决方案?我还使用了substr()函数,但由于文件名长度不相等,因此将常量值传递给substr()函数并不能解决问题。


5
不要解析ls命令的输出,而是使用stat命令。在这里阅读更多信息:http://mywiki.wooledge.org/BashGuide/Practices#Don.27t_Ever_Do_These - Timmah
即使你使用 cd 命令切换到该目录并从那里运行命令,文件名仍然会包含 .txt 后缀。你是想要去除它吗? - kojiro
是的,我想把那个扩展名也删除掉。为此,如果我们能够到达文件名的开头,就可以使用substr()函数将其删除。这就是我最初的想法。 - Amiy
4个回答

8
使用GNU find,您可以执行以下操作以获取不带路径的文件名:
find /apps/dir -type f -printf "%f\n"

正如Kojiro在评论中提到的那样,您可以使用%t%T(format)来获取修改时间。

或者像BroSlow建议的那样操作。

find /apps/dir -printf "%Ab %Ad %AY %f\n"

请勿尝试以下操作(它会在文件名包含空格或在不同操作系统上,ls -l 的表现有更少/更多列时出现错误):
ls -ltr /apps/dir | awk '{n=split($9,f,/\//);print $6,$7,$8,f[n]}'

1
你也可以使用 %t 或 %T(格式)获取 mtime。 - kojiro
1
类似于 find -printf "%Ab %Ad %AY %f\n" 这样的命令应该可以得到他想要的精确格式。 - Reinstate Monica Please
使用%t可以得到时间格式为2016年10月5日星期三18:57:24.0000000000。我该如何将其更改为yyyy-mm-dd h:m:s? - Santosh Pillai
找到所有的.xml文件,并以“%TY-%Tm-%Td %TH:%TM:%TS %Tz %p\n”的格式输出它们的时间戳和路径到tt.txt中,这一招解决了问题。 - Santosh Pillai

2
不要解析ls命令的输出,而是使用stat命令:
stat -c%y filename

这将以可读的格式打印最后修改时间。
或者,如果使用GNU日期,您可以使用带有格式参数和引用标志的日期。
date '+%b %d %Y' -r filename

您可以使用 basename 函数来获取路径中的文件名部分:
basename /path/to/filename

或者按照Kojiro的建议使用参数扩展
要仅获取文件名:
filename="${filename##*/}"

然后,如果有的话,去掉扩展名:
filename="${filename%.*}"

把所有的东西放在一起:
#!/usr/bin/env bash

for filename in *; do
    timestamp=$(stat -c%y "$filename")
    #Uncomment below for a neater timestamp
    #timestamp="${timestamp%.*}"

    filename="${filename##*/}"
    filename="${filename%.*}"

    echo "$timestamp $filename"
done

关于解析ls输出的观点很好。谢谢。 我尝试使用stat -c%n%y /apps/dir,它给了我文件名。虽然这听起来非常愚蠢,但我无法弄清楚如何在此基础上使用basename。你能帮忙吗? - Amiy
你可以使用参数扩展 "${file%.*}" 来获取 basename。无需进行 fork/exec 操作。 - kojiro

0
如果您想要复制“ls”时间格式:
dir=/apps/dir
now=$(date +%s) 
sixmo=$(date -d '6 months ago' +%s)

find "$dir" -maxdepth 1 -print0 | 
while read -d '' -r filename; do 
    mtime=$(stat -c %Y "$filename") 
    if (( sixmo <= mtime && mtime <= now )); then 
        fmt="%b %d %H:%M"
    else 
        fmt="%b %d  %Y"
    fi
    printf "%12s %s\n" "$(date -d "@$mtime" "+$fmt")" "$(basename "$filename")"
done |
sort -k 4

假设使用GNU工具集。

哎呀,有一个尾随的“3”。已修复。 - glenn jackman

0
#!/bin/bash
files=$(find /apps/dir -maxdepth 1 -type f)
for i in $files; do
    file=$(basename $i)
    timestamp=$(stat -c%y $i)
    printf "%-50s %s\n" "$timestamp" "$file" 
done

findls 这样的命令扩展容易出错且不必要。使用 globstar-exec 标志来查找。 - kojiro
这将在包含空格的文件上出错。 - glenn jackman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接