排序-如何在Bash中按排序顺序循环播放所有文件?

我正在使用以下命令循环目录中的所有文件:

for i in *.fas; do some_code; done;

但是,我得到这样的订单:

vvchr1.fas  
vvchr10.fas  
vvchr11.fas

用数字顺序代替vvchr1.fas,vvchr2.fas,vvchr3.fas。

我尝试了排序命令,但没有成功。

Perlnika asked 2020-07-26T18:51:00Z
7个解决方案
86 votes
for i in `ls *.fas | sort -V`; do some_code; done;

其中ls根据man sort做版本排序-文本中自然的(版本)数字排序

同样只使用ls

for i in `ls -v *.fas`; do echo $i; done;
catalin.costache answered 2020-07-26T18:51:18Z
4 votes

您将以ASCII顺序获取文件。 这意味着r早于-k2,2n。我意识到您无法重命名文件(我的生物信息学家的大脑告诉我它们包含染色体数据,而我们根本不将1号染色体称为“ chr01”),因此这是另一种解决方案(不使用-k2,2nr 我在使用的任何操作系统上都找不到):

ls *.fas | sed 's/^\([^0-9]*\)\([0-9]*\)/\1 \2/' | sort -k2,2n | tr -d ' ' |
while read filename; do
  # do work with $filename
done

这有点令人费解,不适用于包含空格的文件名。

另一个解决方案:假设我们想按大小顺序遍历文件,这可能更适合某些生物信息学任务:

du *.fas | sort -k2,2n |
while read filesize filename; do
  # do work with $filename
done

要反转排序,只需在-k2,2n之后添加r(以获得-k2,2nr)。

Kusalananda answered 2020-07-26T18:51:52Z
3 votes

使用选项sort -g时,它将根据常规数值进行比较

 for FILE in `ls ./raw/ | sort -g`; do echo "$FILE"; done

0.log1.日志2.日志...10.日志11.日志

仅当文件名是数字时,这才起作用。 如果它们是字符串,则将按字母顺序获取它们。 例如。:

 for FILE in `ls ./raw/* | sort -g`; do echo "$FILE"; done

raw / 0.lograw / 10.lograw / 11.log...raw / 2.log

gtangil answered 2020-07-26T18:52:25Z
1 votes

您是说列表中编号为10的文件位于编号3之前? 那是因为0非常简单地对其结果进行排序,因此something-10.whatever小于something-3.whatever

一种解决方案是重命名所有文件,使它们具有相同的数字位数(其中具有一位数字的文件以0开头)。

Some programmer dude answered 2020-07-26T18:52:50Z
1 votes
while IFS= read -r  file ; do
    ls -l "$file" # or whatever
done < <(find . -name '*.fas' 2>/dev/null | sed -r -e 's/([0-9]+)/ \1/' | sort -k 2 -n | sed -e 's/ //;'

解决该问题,假定文件命名保持一致,不依赖于最新版本的GNU sort,不依赖于读取ls的输出,并且不会成为管道到同时问题的受害者。

Sorpigal answered 2020-07-26T18:53:10Z
0 votes

就像@Kusalananda的解决方案(也许更容易记住吗?),但可以满足所有文件的需要(?):

array=("$(ls |sed 's/[^0-9]*\([0-9]*\)\..*/\1 &/'| sort -n | sed 's/^[^ ]* //')")
for x in "${array[@]}";do echo "$x";done

从本质上说,添加排序键,排序,删除排序键。

编辑:将评论移至适当的解决方案

potong answered 2020-07-26T18:53:38Z
0 votes

使用sort -rh和while循环

du -sh * | sort -rh | grep -P "avi$" |awk '{print $2}' | while read f; do fp=`pwd`/$f; echo $fp; done;
David Okwii answered 2020-07-26T18:53:58Z
translate from https://stackoverflow.com:/questions/7992689/how-to-loop-all-files-in-sorted-order-in-bash