如何遍历目录中的所有文件,按创建日期排序,有些文件名的名称中有空格
How to iterate through all files in a directory, ordered by date created, with some filenames have spaces in their names
首先我有
for file in `ls -t dir` ; do
#blah
done
但是带空格的文件被分成两个迭代。
我发现了很多解决空格问题的变体,但随后在 $file
变量中留下了一些日期信息。
编辑:展示一个这样的变体:
for file in `find . -printf "%T@ %Tc %p\n" | sort -n` ; do
#blah
done
这个问题是所有时间信息仍然在循环中的 $file
变量中。 (此外,这不起作用,因为我碰巧在 OSX,其 find
实用程序缺少 -printf
选项...)
结合使用find
和xargs
传递文件名以NUL字节分隔,并使用while
读取循环以提高效率和space保存:
find /path/to/dir -type f -print0 | xargs -0 ls -t | while read file
do
ls "$file" # or whatever you want with $file, which may have spaces
# so always enclose it in double quotes
done
find
生成文件列表,ls
在这种情况下按时间排列它们。要反转排序顺序,请将 -t
替换为 -tr
。如果您想按大小排序,请将 -t
替换为 -s
。
示例:
$ touch -d '2015-06-17' 'foo foo'
$ touch -d '2016-02-12' 'bar bar'
$ touch -d '2016-05-01' 'baz baz'
$ ls -1
bar bar
baz baz
foo foo
$ find . -type f -print0 | xargs -0 ls -t | while read file
> do
> ls -l "$file"
> done
-rw-rw-r-- 1 bishop bishop 0 May 1 00:00 ./baz baz
-rw-rw-r-- 1 bishop bishop 0 Feb 12 00:00 ./bar bar
-rw-rw-r-- 1 bishop bishop 0 Jun 17 2015 ./foo foo
为了完整起见,我将突出问题评论中的一点:-t
是按修改时间排序,严格来说不是创建时间。这些文件所在的文件系统决定了创建时间是否可用。由于您最初的尝试使用 -t
,我认为修改时间是您所关心的,即使它不是迂腐的真实。
如果你想要创建时间,你必须从一些来源中提取它,比如 stat
或者文件名,如果它在那里编码的话。这基本上意味着用管道传送到 sort
的合适命令替换 xargs -0 ls -t
,例如:xargs -0 stat -c '%W' | sort -n
您可以临时设置 IFS 变量以避免空格问题(感谢 http://www.linuxjournal.com/article/10954?page=0,1)
IFS_backup=$IFS
IFS=$(echo -en "\n\b")
for file in `ls -t dir` ; do
#blah
done
IFS=$IFS_backup
编辑:这适用于 Ubuntu,但不适用于 RHEL6。 bishop 建议的替代方案似乎更便携,例如:
ls -t dir|while read file; do ...; done
使用 GNU find
和 GNU sort
,可以执行以下操作:
while IFS='' read -r -d ' ' mtime && IFS='' read -r -d '' filename; do
printf 'Processing file %q with timestamp of %s\n' "$filename" "$mtime"
done < <(find "$dir" -type f -printf '%T@ %p[=10=]' | sort -znr)
其工作原理如下:
find
以 <seconds-since-epoch> <filename><NUL>
. 格式打印其输出
sort
对其进行数字排序——因此,按修改时间,以自纪元以来的秒数表示。
IFS='' read -r -d ' ' mtime
将 space 之前的所有内容读入变量 mtime
.
IFS='' read -r -d '' filename
将直到 NUL 的所有剩余内容读入变量 filename
因为 NUL 不能存在于文件名中(与换行符相比,可以),这不能被内容令人惊讶的名称所忽略。有关详细讨论,请参阅 BashFAQ #3。
此外,因为它不依赖于将名称作为命令行参数传递给 ls -t
(与所有其他外部命令一样,它在每次调用时只能接受有限数量的命令行参数),这种方法不受它可以可靠排序的文件数量的限制。 (当正在处理的文件名数量大于可以传递给单个 ls
调用的数量时,使用 find ... -exec ls -t {} +
或 ... | xargs ls -t
将导致不正确的结果。
首先我有
for file in `ls -t dir` ; do
#blah
done
但是带空格的文件被分成两个迭代。
我发现了很多解决空格问题的变体,但随后在 $file
变量中留下了一些日期信息。
编辑:展示一个这样的变体:
for file in `find . -printf "%T@ %Tc %p\n" | sort -n` ; do
#blah
done
这个问题是所有时间信息仍然在循环中的 $file
变量中。 (此外,这不起作用,因为我碰巧在 OSX,其 find
实用程序缺少 -printf
选项...)
结合使用find
和xargs
传递文件名以NUL字节分隔,并使用while
读取循环以提高效率和space保存:
find /path/to/dir -type f -print0 | xargs -0 ls -t | while read file
do
ls "$file" # or whatever you want with $file, which may have spaces
# so always enclose it in double quotes
done
find
生成文件列表,ls
在这种情况下按时间排列它们。要反转排序顺序,请将 -t
替换为 -tr
。如果您想按大小排序,请将 -t
替换为 -s
。
示例:
$ touch -d '2015-06-17' 'foo foo'
$ touch -d '2016-02-12' 'bar bar'
$ touch -d '2016-05-01' 'baz baz'
$ ls -1
bar bar
baz baz
foo foo
$ find . -type f -print0 | xargs -0 ls -t | while read file
> do
> ls -l "$file"
> done
-rw-rw-r-- 1 bishop bishop 0 May 1 00:00 ./baz baz
-rw-rw-r-- 1 bishop bishop 0 Feb 12 00:00 ./bar bar
-rw-rw-r-- 1 bishop bishop 0 Jun 17 2015 ./foo foo
为了完整起见,我将突出问题评论中的一点:-t
是按修改时间排序,严格来说不是创建时间。这些文件所在的文件系统决定了创建时间是否可用。由于您最初的尝试使用 -t
,我认为修改时间是您所关心的,即使它不是迂腐的真实。
如果你想要创建时间,你必须从一些来源中提取它,比如 stat
或者文件名,如果它在那里编码的话。这基本上意味着用管道传送到 sort
的合适命令替换 xargs -0 ls -t
,例如:xargs -0 stat -c '%W' | sort -n
您可以临时设置 IFS 变量以避免空格问题(感谢 http://www.linuxjournal.com/article/10954?page=0,1)
IFS_backup=$IFS
IFS=$(echo -en "\n\b")
for file in `ls -t dir` ; do
#blah
done
IFS=$IFS_backup
编辑:这适用于 Ubuntu,但不适用于 RHEL6。 bishop 建议的替代方案似乎更便携,例如:
ls -t dir|while read file; do ...; done
使用 GNU find
和 GNU sort
,可以执行以下操作:
while IFS='' read -r -d ' ' mtime && IFS='' read -r -d '' filename; do
printf 'Processing file %q with timestamp of %s\n' "$filename" "$mtime"
done < <(find "$dir" -type f -printf '%T@ %p[=10=]' | sort -znr)
其工作原理如下:
find
以<seconds-since-epoch> <filename><NUL>
. 格式打印其输出
sort
对其进行数字排序——因此,按修改时间,以自纪元以来的秒数表示。IFS='' read -r -d ' ' mtime
将 space 之前的所有内容读入变量mtime
.IFS='' read -r -d '' filename
将直到 NUL 的所有剩余内容读入变量filename
因为 NUL 不能存在于文件名中(与换行符相比,可以),这不能被内容令人惊讶的名称所忽略。有关详细讨论,请参阅 BashFAQ #3。
此外,因为它不依赖于将名称作为命令行参数传递给 ls -t
(与所有其他外部命令一样,它在每次调用时只能接受有限数量的命令行参数),这种方法不受它可以可靠排序的文件数量的限制。 (当正在处理的文件名数量大于可以传递给单个 ls
调用的数量时,使用 find ... -exec ls -t {} +
或 ... | xargs ls -t
将导致不正确的结果。