且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

通过文件名列表,以便他们迭代在bash创建

更新时间:2023-12-04 20:01:34

  sorthelper =();
在*文件;做
    #我们需要的东西,可以很容易地进行排序。
    #在这里,我们用<日期和GT;<&名GT;。
    #注意这与在文件名中的任何特殊字符    sorthelper + =($(STAT -n -f%钐%N-t%Y%M%D%H%M%S - $文件));只有#的Mac OS X
    # 要么
    sorthelper + =($(统计--printf%Y%N - $文件));唯一的Linux#
完成的;排序=();
而读-d $'\\ 0'ELEM;做
    #这个除掉的前14个字符(小于日期>)
    分类+ =($ {ELEM:14});
完成< ≤(printf的'%S \\ 0'$ {sorthelper [@]}|排序-z)在文件$ {分类[@]};做
    #做你的东西...
    回声$文件;
完成的;

除了排序统计,所有的命令都是实际的本机猛砸命令(内建)*。如果你真的想要,可以实现自己的排序使用bash内建命令只的,但我看到没有摆脱与stat方式

重要的部分是读-d $'\\ 0'的printf'%s的\\ 0'排序-z 。所有这些命令与它们空定界符选项使用,这意味着,任何文件名可以安全procesed。此外,在使用双引号的$文件$ {anarray [*]}是是必不可少的。

* 很多人都觉得GNU工具都弄好猛砸的一部分,但在技术上他们没有。因此,统计排序是一样的非本地为 perl的

Parsing output of ls to iterate through list of files is bad. So how should I go about iterating through list of files in order by which they were first created? I browsed several questions here on SO and they all seem to parsing ls.

The embedded link suggests:

Things get more difficult if you wanted some specific sorting that only ls can do, such as ordering by mtime. If you want the oldest or newest file in a directory, don't use ls -t | head -1 -- read Bash FAQ 99 instead. If you truly need a list of all the files in a directory in order by mtime so that you can process them in sequence, switch to perl, and have your perl program do its own directory opening and sorting. Then do the processing in the perl program, or -- worst case scenario -- have the perl program spit out the filenames with NUL delimiters.

Even better, put the modification time in the filename, in YYYYMMDD format, so that glob order is also mtime order. Then you don't need ls or perl or anything. (The vast majority of cases where people want the oldest or newest file in a directory can be solved just by doing this.)

Does that mean there is no native way of doing it in bash? I don't have the liberty to modify the filename to include the time in them. I need to schedule a script in cron that would run every 5 minutes, generate an array containing all the files in a particular directory ordered by their creation time and perform some actions on the filenames and move them to another location.

The following worked but only because I don't have funny filenames. The files are created by a server so it will never have special characters, spaces, newlines etc.

files=( $(ls -1tr) ) 

I can write a perl script that would do what I need but I would appreciate if someone can suggest the right way to do it in bash. Portable option would be great but solution using latest GNU utilities will not be a problem either.

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;

Other than sort and stat, all commands are actual native Bash commands (builtins)*. If you really want, you can implement your own sort using Bash builtins only, but I see no way of getting rid of stat.

The important parts are read -d $'\0', printf '%s\0' and sort -z. All these commands are used with their null-delimiter options, which means that any filename can be procesed safely. Also, the use of double-quotes in "$file" and "${anarray[*]}" is essential.

*Many people feel that the GNU tools are somehow part of Bash, but technically they're not. So, stat and sort are just as non-native as perl.