我正在编写一个应用程序,先决条件之一是能够查看多个目录并找到每个文件的最新版本。
我已经成功使用ls
和find
来获取最新文件,但如果这些相同的文件位于多个目录中,则不是每个文件的最新版本。需要注意的一点是,我不一定知道这些文件的名称,但会知道目录的名称。
例子:DIR1、DIR2 和 DIR3 各自包含 FileA 和 FileB 的版本。我需要所有三个(或更多)目录中包含的 FileA 和 FileB 的最新版本。
有人有主意吗?
答案1
您选择的工具是正确的:
ls -t
是按时间排序文件的好方法,这样您就可以挑选最新的find
是在目录和子目录中查找与某些模式匹配的文件的正确工具
当然,棘手的部分是您需要按文件名进行某种分组,并在每个组中选择最新的文件。由于这个要求,我认为您需要一个循环,在其中迭代每个目标文件名以查找其最新版本。
假设文件位于$dir1
、$dir2
或中$dir3
,您可以编写一个函数来查找某些模式的最新版本,如下所示:
find_latest() {
pattern=$1
ls -t "$dir1/$pattern" "$dir2/$pattern" "$dir3/$pattern" | head -n 1
}
然后假设您有模式access.log
, error.log
, x*
,那么您可以像这样循环它们,例如:
for pattern in access.log error.log 'x*'; do
latest=$(find_latest 'a*')
echo $latest
done
如果上述假设不成立,并且文件可以位于$dir1
、$dir2
或的子目录中$dir3
,那么您需要使用find
,它会变得有点复杂:
find_latest() {
pattern=$1
find "$dir1" "$dir2" "$dir3" -name "$pattern" -print0 | xargs -0 ls -t | head -n 1
}
有一个小警告:如果路径包含换行符,此函数将无法正常工作,因为该head -n 1
步骤将截断换行符之后的路径部分。我祈祷你没有这样的路;-)
答案2
您可以通过以下方式执行此操作pax
:
pax -wrtvZs"|.*/||p" ./DIR[123] "$PWD"
所以我会尝试通过论证来分解它:
-wr
- 这些是w
rite 和r
ead,它们一起意味着pax
应该复制文件而不是归档。您也可以放弃副本,只使用-l
.-t
pax
- 这会将所有文件访问时间重置为读取文件以检查其元数据之前的状态。-v
- 工作很冗长。-Z
- 在所有可能的名称替换完成之前,不会比较源文件的 mod 时间。- 它是这个(以及接下来的事情)这使得这一切变得如此简单。如果没有这个 - 可能您在其他地方会遇到的问题 - 是
DIR1/FILEA
不同DIR2/FILEA
的文件,即使它们共享基本名称。所以如果没有这个,他们永远不会被比较......
- 它是这个(以及接下来的事情)这使得这一切变得如此简单。如果没有这个 - 可能您在其他地方会遇到的问题 - 是
-s
- 用标准正则表达式替换文件名的一部分sed
。- 在这里,我只是将每个文件的所有部分减少为其基本名称,因此
-Z
适用于全部FILEA
s 并且仅将最新的复制到"$PWD"
.
- 在这里,我只是将每个文件的所有部分减少为其基本名称,因此
我使用以下测试来验证这一切:
for d in DIR3 DIR1 DIR2
do cd ~; mkdir -p "$d"; cd "$d"
sleep 90; touch FILEB FILEA
done; cd ~
...获取测试集。以下是最终的修改时间:
ls -l ./DIR[123]/FILE[AB]
-rw-r--r-- 1 mikeserv mikeserv 0 Dec 20 03:28 ./DIR1/FILEA
-rw-r--r-- 1 mikeserv mikeserv 0 Dec 20 03:28 ./DIR1/FILEB
-rw-r--r-- 1 mikeserv mikeserv 0 Dec 20 03:29 ./DIR2/FILEA
-rw-r--r-- 1 mikeserv mikeserv 0 Dec 20 03:29 ./DIR2/FILEB
-rw-r--r-- 1 mikeserv mikeserv 0 Dec 20 03:26 ./DIR3/FILEA
-rw-r--r-- 1 mikeserv mikeserv 0 Dec 20 03:26 ./DIR3/FILEB
所以,当我跑步时:
pax -wrtvZs"|.*/||p" ./DIR[123] "$PWD"
ls -l ./FILE[AB]
...输出是...
./DIR1/FILEA >> FILEA
/home/mikeserv/FILEA
./DIR1/FILEB >> FILEB
/home/mikeserv/FILEB
./DIR2/FILEA >> FILEA
/home/mikeserv/FILEA
./DIR2/FILEB >> FILEB
/home/mikeserv/FILEB
./DIR3/FILEA >> FILEA
./DIR3/FILEB >> FILEB
-rw-r--r-- 1 mikeserv mikeserv 0 Dec 20 03:29 ./FILEA
-rw-r--r-- 1 mikeserv mikeserv 0 Dec 20 03:29 ./FILEB
你可以看到它发生。当-s|||p
更改文件名时p
,修饰符会向stderr
.因此,我们看到DIR1
文件首先被评估 - 并复制到$PWD
,然后DIR2
文件得到相同的处理 - 但DIR3
文件没有被复制,因为$PWD/FILE[AB]
现在比它们新。