解析输出ls以遍历文件列表是不好的.那么我应该如何按照它们首次创建的顺序迭代文件列表?我在这里浏览了几个问题,他们似乎都解析了ls.
嵌入式链接表明:
如果你想要一些只能
ls做的特定排序,例如排序,事情变得更加困难mtime.如果您想要目录中最旧或最新的文件,请不要使用ls -t | head -1- 请参阅Bash FAQ 99.如果您确实需要mtime按顺序列出目录中的所有文件,以便按顺序处理它们,请切换到perl,并让perl程序执行自己的目录打开和排序.然后在perl程序中进行处理,或者 - 最坏的情况 - 让perl程序用NUL分隔符吐出文件名.更好的是,将修改时间放在YYYYMMDD格式的文件名中,这样glob顺序也是mtime顺序.然后你不需要ls或perl或任何东西.(人们想要目录中最旧或最新文件的绝大多数情况都可以通过这样做来解决.)
这是否意味着没有本地方式可以做到这一点bash?我没有权限修改文件名以包含时间.我需要安排一个cron每5分钟运行一次的脚本,生成一个数组,其中包含按创建时间排序的特定目录中的所有文件,并对文件名执行一些操作并将它们移动到另一个位置.
以下工作但只是因为我没有有趣的文件名.这些文件是由服务器创建的,因此它永远不会有特殊字符,空格,换行符等.
files=( $(ls -1tr) )
Run Code Online (Sandbox Code Playgroud)
我可以编写一个perl可以满足我需要的脚本,但如果有人可以提出正确的方法,我会很感激bash.便携式选项会很棒,但使用最新GNU实用程序的解决方案也不会成为问题.
sorthelper=();
for file in *; do
# We need something that can easily be sorted.
# Here, we use "<date><filename>".
# Note that this works with any special characters in filenames
sorthelper+=("$(stat -n -f "%Sm%N" -t "%Y%m%d%H%M%S" -- "$file")"); # Mac OS X only
# or
sorthelper+=("$(stat --printf "%Y %n" -- "$file")"); # Linux only
done;
sorted=();
while read -d $'\0' elem; do
# this strips away the first 14 characters (<date>)
sorted+=("${elem:14}");
done < <(printf '%s\0' "${sorthelper[@]}" | sort -z)
for file in "${sorted[@]}"; do
# do your stuff...
echo "$file";
done;
Run Code Online (Sandbox Code Playgroud)
除了sort和之外stat,所有命令都是实际的本机Bash命令(builtins)*.如果你真的想要,你可以使用Bash builtins 实现自己的sort,但我认为没有办法摆脱stat.
重要的部分是read -d $'\0',printf '%s\0'和sort -z.所有这些命令都与其null分隔符选项一起使用,这意味着可以安全地处理任何文件名.此外,使用双引号"$file"并且"${anarray[*]}"是必不可少的.
*许多人认为GNU工具在某种程度上是Bash的一部分,但从技术上讲它们不是.所以,stat和sort非原生一样perl.
尽管有所有反对使用解析目录的警告和警告,但我们都发现自己处于这种情况。ls如果您确实发现自己需要排序的目录输入,那么最干净的用法ls是为您的循环提供数据,这将处理文件名等中的空格。由于其本身的性质,ls -opts | read -r name; do...不需要重置。例子:IFSread
ls -1rt | while read -r fname; do # where '1' is ONE not little 'L'
Run Code Online (Sandbox Code Playgroud)
因此,一定要寻找更清洁的解决方案来避免ls,但如果到了紧要关头,ls -opts可以谨慎使用,而不会天塌下来或龙把你的眼睛挖出来。
让我添加免责声明,以使大家满意。如果您喜欢newlines在文件名中使用 - 那么不要使用ls它来填充循环。如果您的文件名中没有newlines,则不会有其他不利的副作用。
魂斗罗: TLDP Bash Howto 简介:
#!/bin/bash
for i in $( ls ); do
echo item: $i
done
Run Code Online (Sandbox Code Playgroud)
看来 SO 用户不知道contra的使用意味着什么——请在投票之前先查一下。