背景:我目前正在编写一个归档脚本,该脚本从某些文件夹及其内容创建压缩的 tarball。它应该能够将 gzip 压缩的存档与源同步,而无需解压缩存档或压缩源。为此,寻求的解决方案是将 的输出ls -l
与 的输出同步tar -ztvf
。
这两个命令都返回类似的输出,但略有不同。大多数差异可以通过正则表达式或 来解决cut
。我无法轻松解决的一件事是以最大深度列出相对于查询目录的文件路径。
为了克服这个问题,我曾经找到每个文件,并使用以下命令find
将它们输入:ls
find Webcam -exec ls -lR --time-style="+%Y-%m-%d %H:%M" {} \; | cut -f1,3- -d" " | sed "s/ /\//2" | sed "s/ \+/ /g"
其中大部分管道用于格式化目的,find Webcam -exec ls -lR {} \;
是有问题的部分,并且Webcam
是测试文件夹。该命令的输出如下:
-rw-r--r-- debian/debian 162406 2014-04-12 13:42 2014-04-12-134210.jpg
-rw-r--r-- debian/debian 116247 2014-08-09 16:38 2014-08-09-163849.jpg
-rw-r--r-- debian/debian 96597 2015-03-15 19:39 2015-03-15-193905.jpg
-rw-r--r-- debian/debian 100795 2015-04-29 20:23 2015-04-29-202242.jpg
-rw-r--r-- debian/debian 97120 2015-08-02 13:42 2015-08-02-134230.jpg
-rw-r--r-- debian/debian 123835 2015-08-27 23:03 2015-08-27-230306.jpg
-rw-r--r-- debian/debian 97120 2015-08-02 13:42 Webcam/2015-08-02-134230.jpg
-rw-r--r-- debian/debian 100795 2015-04-29 20:23 Webcam/2015-04-29-202242.jpg
-rw-r--r-- debian/debian 116247 2014-08-09 16:38 Webcam/2014-08-09-163849.jpg
-rw-r--r-- debian/debian 96597 2015-03-15 19:39 Webcam/2015-03-15-193905.jpg
-rw-r--r-- debian/debian 162406 2014-04-12 13:42 Webcam/2014-04-12-134210.jpg
-rw-r--r-- debian/debian 123835 2015-08-27 23:03 Webcam/2015-08-27-230306.jpg
现在的输出类似于tar -ztvf
:
-rw-r--r-- debian/debian 162406 2014-04-12 13:42 Webcam/2014-04-12-134210.jpg
-rw-r--r-- debian/debian 116247 2014-08-09 16:38 Webcam/2014-08-09-163849.jpg
-rw-r--r-- debian/debian 96597 2015-03-15 19:39 Webcam/2015-03-15-193905.jpg
-rw-r--r-- debian/debian 100795 2015-04-29 20:23 Webcam/2015-04-29-202242.jpg
-rw-r--r-- debian/debian 97120 2015-08-02 13:42 Webcam/2015-08-02-134230.jpg
-rw-r--r-- debian/debian 123835 2015-08-27 23:03 Webcam/2015-08-27-230306.jpg
明显的缺陷是ls
将每个找到的项目列出两次,一次包含所需的路径,一次没有它。我如何“修复”ls
将每个项目列出两次?
关于此错误的性质(例如,幕后发生的情况)的其他见解非常受欢迎,同时也欢迎作为旁注解决整个归档问题的更实用的方法。然而,现在我认为这是一个挑战,我想解决它,所以主要重点应该放在限制ls
.
答案1
问题是 findWebcam
也找到了目录,并运行ls Webcam
它列出了那里的所有文件。要仅列出文件,而不列出目录,请告诉 find
-type f
答案2
您的问题是ls -lR
将对所有文件(将显示文件)和每个目录(将显示目录的内容)执行。如果您的目录层次结构不是扁平的,而是包含子目录,则这会更频繁地显示内容,就像再次遍历子目录一样-R
。ls
相反,您应该find
按如下方式调用:
find . -type f -exec ls -l {}
,这只会显示文件。find . -exec ls -dl {}
,它将显示文件和目录。
答案3
这个问题的根本原因非常短:(.
是的:一个点)。
了解find
(没有目录)相当于find .
.从man find
:
如果未给出路径,则使用当前目录。
并且,当您执行时,find .
点会出现在生成的列表中
(仅使用四个具有不同名称的文件以使其简单):
$ find ### Works the same with or without the dot.
.
./2014-08-09-163849.jpg
./2014-04-12-134210.jpg
./Webcam
./Webcam/2015-04-29-202242.jpg
./Webcam/2015-08-27-230306.jpg
然后你将这个列表提供给ls -R
(递归地)。
只需点即可重现所有文件:
$ ls -1R . ### The 1 will make the list 1 column.
.:
Webcam
2014-04-12-134210.jpg
2014-08-09-163849.jpg
./Webcam:
2015-04-29-202242.jpg
2015-08-27-230306.jpg
因此,难怪所有文件都会出现两次(一次用于点,一次来自查找)。
$ find -exec ls -1R {} \;
.:
2014-04-12-134210.jpg
2014-08-09-163849.jpg
Webcam
./Webcam:
2015-04-29-202242.jpg
2015-08-27-230306.jpg
./2014-08-09-163849.jpg
./2014-04-12-134210.jpg
./Webcam:
2015-04-29-202242.jpg
2015-08-27-230306.jpg
./Webcam/2015-04-29-202242.jpg
./Webcam/2015-08-27-230306.jpg
解决方案
删除点(使用\( ! -name . -prune \) -a
)。
从 find 找到的文件列表中删除点:
$ find . \( ! -name . -prune \) -a -print
./2014-08-09-163849.jpg
./2014-04-12-134210.jpg
./Webcam
然后你可以使用递归ls -R
:
$ find . \( ! -name . -prune \) -a -exec ls -1R {} \;
./2014-08-09-163849.jpg
./2014-04-12-134210.jpg
./Webcam:
2015-04-29-202242.jpg
2015-08-27-230306.jpg
避免递归 ls (更简单但要求ls -d
)。
不使用递归ls -R
(还有-d
避免扩展到目录的选项)并让find
我们遍历树来查找所有文件:
$ find . ! -path . -exec ls -1d {} \;
./2014-08-09-163849.jpg
./2014-04-12-134210.jpg
./Webcam
./Webcam/2015-04-29-202242.jpg
./Webcam/2015-08-27-230306.jpg
归档
当然,对于归档的具体使用:
您不需要目录名称,只需要完整路径文件名:
$ find . ! -path ./ -type f -a -exec ls -1R {} \;
./2014-08-09-163849.jpg
./2014-04-12-134210.jpg
./Webcam/2015-04-29-202242.jpg
./Webcam/2015-08-27-230306.jpg
关于find dir
(不是点)。
如果您使用路径,则当目录深度大于 1 时,问题是相同的。
这不会引发问题:
$ find Webcam -exec ls -1R {} \;
Webcam:
2015-04-29-202242.jpg
2015-08-27-230306.jpg
Webcam/2015-04-29-202242.jpg
Webcam/2015-08-27-230306.jpg
然而,将深度增加一 (cd ..) 将:
$ cd ..
$ find jpg -exec ls -1R {} \;
jpg:
2014-04-12-134210.jpg
2014-08-09-163849.jpg
Webcam
jpg/Webcam:
2015-04-29-202242.jpg
2015-08-27-230306.jpg
jpg/2014-08-09-163849.jpg
jpg/2014-04-12-134210.jpg
jpg/Webcam:
2015-04-29-202242.jpg
2015-08-27-230306.jpg
jpg/Webcam/2015-04-29-202242.jpg
jpg/Webcam/2015-08-27-230306.jpg
这不会触发:
$ find jpg \( ! -path ./jpg -prune \) -exec ls -1R {} \;
jpg:
2014-04-12-134210.jpg
2014-08-09-163849.jpg
Webcam
jpg/Webcam:
2015-04-29-202242.jpg
2015-08-27-230306.jpg
我坚持认为使用两个递归工具是非常不明智。
更改为更简单的结构,例如find jpg -ls
甚至尝试使用 shell 提供的列表解决方案,类似于echo **
:
$ (shopt -s globstar nullglob; printf '%s\n' jpg/**/*)
jpg/2014-04-12-134210.jpg
jpg/2014-08-09-163849.jpg
jpg/Webcam
jpg/Webcam/2015-04-29-202242.jpg
jpg/Webcam/2015-08-27-230306.jpg