【问题标题】:Extracting filename & modification time from ls output从 ls 输出中提取文件名和修改时间
【发布时间】:2014-03-28 12:16:28
【问题描述】:

我在一个目录中有一组文件。我只想从 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 到该目录并从那里运行命令,但是没有 cd 是否有可能的解决方案?我也使用了 substr() 但由于文件名的长度不相等,因此将常量值传递给 substr() 函数没有成功。

【问题讨论】:

  • 不要解析 ls 命令的输出,而是使用 stat。阅读here
  • 即使您 cd 到目录并从那里运行命令,您仍然会在文件名上获得 .txt。你想去掉那个吗?
  • 是的,我也想删除该扩展名。为此,如果我们可以到达文件名的开头,我们可以使用 substr() 删除它。这就是我最初的想法。

标签: linux bash shell awk


【解决方案1】:

使用GNU find,您可以执行以下操作来获取不带路径的文件名:

find /apps/dir -type f -printf "%f\n"

正如cmets中提到的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]}'

【讨论】:

  • 对了,你也可以用 %t 或者 %T(format) 来获取mtime。
  • find -printf "%Ab %Ad %AY %f\n" 这样的东西会得到我认为他想要的确切格式。
  • 使用 %t 我得到时间格式为 Wed Oct 5 18:57:24.0000000000 2016。如何将其更改为 yyyy-mm-dd h:m:s
  • find *.xml -type f -printf "%TY-%Tm-%Td %TH:%TM:%TS %Tz %p\n">tt.txt 成功了跨度>
【解决方案2】:

Dont解析ls命令的输出,而不是使用stat:

stat -c%y filename

这将以人类可读的格式打印最后修改时间

或者如果使用 GNU 日期,您可以使用带有格式参数和引用标志的日期

date '+%b %d %Y' -r filename

您可以使用 basename 来获取路径的文件名部分:

basename /path/to/filename

或者正如 Kojiro 建议的 parameter expansion

仅获取文件名:

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。请你帮忙。
  • 可以通过参数扩展"${file%.*}"得到basename。无需分叉/执行。
【解决方案3】:
#!/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 标志find
  • 这会破坏包含空格的文件。
【解决方案4】:

如果要复现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”。固定
猜你喜欢
  • 2012-12-09
  • 1970-01-01
  • 1970-01-01
  • 2015-06-07
  • 1970-01-01
  • 1970-01-01
  • 2013-05-11
  • 2021-03-28
  • 2017-02-06
相关资源
最近更新 更多