文件名、最后修改日期、脚本中的shell。

12

我正在使用Bash编写脚本,其中我将在变量中获取文件名,然后使用该变量获取文件的Unix最后修改日期。

我需要获取此修改日期值,但无法使用stat命令。

您知道使用常见的*nix命令获取它的任何方法吗?


如果可能的话,使用可配置的日期格式。 - odew
1
你为什么不能使用 stat - Sean Bright
我目前工作的环境中没有可用的stat。 - odew
如果我的答案不起作用(date 不支持 -r 标志),能否提供更具体的平台信息 - 您已经标记了 LinuxUnixstatdate 在我遇到的各种 Linux 发行版中都非常普遍(据我所知)。 - simont
我需要一个便携或强大的解决方案,我在一个HP-UX系统中,这个脚本也应该能在Linux上运行。不要用perl。 - odew
5个回答

18

为什么你不应该使用ls

解析ls是个坏主意。不仅某些文件名中的字符行为未定义且依赖于平台,而且在你的目的下,它会干扰六个月前的日期。简而言之,是的,在有限的测试中,它可能对你有效。它将不会是平台无关的(因此不具备可移植性),并且由于各种系统上“合法”文件名的范围,您的解析行为不能得到保证。 (例如,Ext4允许文件名中包含空格和换行符)。

尽管如此,就个人而言,我会使用ls,因为它快速简单 ;)

编辑

正如评论中Hugo所指出的那样,OP不想使用stat。此外,我应该指出以下部分是BSD-stat特定的(当我在Ubuntu上测试时,%Sm标志无法工作;Linux有一个stat命令,如果您对它感兴趣,请阅读man page)。

因此,非stat解决方案:使用date

date,至少在Linux上,具有一个标志:-r,根据man page的说法:

显示文件的最后修改时间

因此,脚本化的解决方案类似于这样:

date -r ${MY_FILE_VARIABLE}

你将会得到类似于这样的返回结果:
zsh% date -r MyFile.foo
Thu Feb 23 07:41:27 CST 2012

针对OP的评论:

如果可能,需要可配置日期格式

date具有相当广泛的时间格式变量;请阅读man页面以获取更多信息。

我不确定date在所有“类Unix系统”上的可移植性。对于基于BSD的系统(例如OS X),这将无法工作;BSD-date的-r标志会执行完全不同的操作。问题没有明确规定需要多可移植的解决方案。对于基于BSD的解决方案,请参见下面的部分;)

更好的解决方案,BSD系统(在OS X上使用BSD-stat进行测试;GNU stat略有不同,但可以以相同方式工作)。

使用stat。您可以使用-f标志格式化stat的输出,并选择仅显示文件修改数据(对于此问题很好)。

例如,stat -f“%m%t%Sm%N” ./*


1340738054  Jun 26 21:14:14 2012 ./build
1340738921  Jun 26 21:28:41 2012 ./build.xml
1340738140  Jun 26 21:15:40 2012 ./lib
1340657124  Jun 25 22:45:24 2012 ./tests

这个命令的第一位是UNIX纪元时间,日期是文件修改时间,其余是文件名。

示例命令的分解

stat -f "%m%t%Sm %N" ./*

  1. stat -f:调用stat并指定格式(-f)。
  2. %m:UNIX纪元时间。
  3. %t:输出中的制表符分隔符。
  4. %SmS表示将输出显示为stringm表示使用文件修改数据。
  5. %N:显示所讨论文件的名称。

你的脚本中的一个命令如下:

stat -f "%Sm" ${FILE_VARIABLE}

将会给你输出,例如:

Jun 26 21:28:41 2012

阅读 statman page 以获取更多信息;时间戳格式化由 strftime 完成。


1
我会为你的“不要使用ls”部分点赞,但是op确实说他不能使用stat,因为他需要这个程序在任何类Unix操作系统上都能运行。 - WhyNotHugo
日期函数 date 在 BSD 操作系统上不可用(已在 OpenBSD 上测试)。而 stat 函数可以使用,但在 Linux 上可能会有问题。 - WhyNotHugo
2
你抱怨ls -l不可移植,但date更不可移植。问题在于BSD系统也使用-r参数,但用于不同的目的。换句话说,使用-r可能会得到一个有效的命令(退出状态=0),但却无法获得想要的结果。 - David W.
@DavidW。答案提到date在基于BSD的系统上不可移植。使用ls不可移植因为它不能保证在任何平台上都能工作。这与datestat形成对比,因为这两个工具的文档实现因平台而异 - 它们是不同的工具。ls是相同的工具,对于合法输入具有未定义的行为。(虽然我个人会使用ls...) 我不确定是否有一个好的、跨平台的解决方案来解决这种类型的问题。 - simont
如果current是一个指向目录的符号链接,stat current将会给出关于链接本身的信息,stat current/将会给出关于链接目录的信息,但是date -f currentdate -f current/都将会给出关于被链接的目录的信息,因此你无法通过使用date来获取符号链接本身的时间。 - Jānis Elmeris
显示剩余2条评论

4

有Perl吗?

perl -MFile::stat -e "print scalar localtime stat('FileName.txt')->mtime"

3
如何处理:
find $PATH -maxdepth 1 -name $FILE -printf %Tc

请参考find手册,了解可与%T一起使用的其他值。

1
您可以使用“date”命令并添加所需的格式选项来设置日期格式:
 date +%Y-%m-%d -r /root/foo.txt

2013年5月27日
 date +%H:%M -r /root/foo.txt

23:02

-2

您可以使用 ls -l 命令列出最后修改时间,然后使用 cut 命令剪切出修改日期:

mod_date=$(ls -l $file_name | cut -c35-46)

这在我的系统上有效,因为日期出现在第35到46列之间。您可能需要在您的系统上进行调整。

日期有两种不同的格式:

  • Mmm dd hh:mm
  • Mmm dd yyyy

超过一年前修改的文件将具有后一种格式。少于一年前修改的文件将具有第一种格式。您可以搜索“:”并知道文件所处的格式:

if echo "$mod_date" | grep -q ":"
then
    echo "File was modified within the year"
else
    echo "File was modified more than a year ago"
fi

解析 ls 通常被认为是不良实践。虽然它(可能)可以正常工作,但不能保证其可移植性或健壮性。 - simont
@simont 那解决方案呢?你应该使用通用的 shell 脚本和更多或更少标准的工具,这意味着你不能使用像 Perl 或 Python 这样的脚本语言。你也不能使用 stat。在这些限制下,除了解析 ls 之外,没有太多选择了。正如我在帖子中所述,它可能在 OP 的系统上不完全相同。 - David W.

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