我正在使用以下命令遍历目录中的所有文件:
for i in *.fas; do some_code; done;
然而,我按照这个顺序获取到它们
vvchr1.fas
vvchr10.fas
vvchr11.fas
vvchr2.fas
...
替代
vvchr1.fas
vvchr2.fas
vvchr3.fas
...
什么是自然顺序。
我尝试过 sort 命令,但没有成功。
我正在使用以下命令遍历目录中的所有文件:
for i in *.fas; do some_code; done;
然而,我按照这个顺序获取到它们
vvchr1.fas
vvchr10.fas
vvchr11.fas
vvchr2.fas
...
替代
vvchr1.fas
vvchr2.fas
vvchr3.fas
...
什么是自然顺序。
我尝试过 sort 命令,但没有成功。
readarray -d '' entries < <(printf '%s\0' *.fas | sort -zV)
for entry in "${entries[@]}"; do
# do something with $entry
done
执行 printf '%s\0' *.fas
命令会返回一个以 NUL 分隔的目录列表,该列表包含后缀为 .fas
的文件名。然后使用 sort -zV
命令按自然排序对它们进行排序。
请注意,需要安装 GNU sort 才能使此方法生效。
通过选项sort -g进行排序时,它会按照一般数值进行比较。
for FILE in `ls ./raw/ | sort -g`; do echo "$FILE"; done
0.log 1.log 2.log ... 10.log 11.log
只有当文件名为数字时才能正常工作。如果它们是字符串,则会按字母顺序排序。例如:
for FILE in `ls ./raw/* | sort -g`; do echo "$FILE"; done
原始/0.log 原始/10.log 原始/11.log ... 原始/2.log
您将按ASCII顺序获取文件。这意味着vvchr10*
会在vvchr2*
之前出现。我了解您不能重命名文件(我的生物信息学大脑告诉我它们包含染色体数据,我们根本不称染色体1为“chr01”),所以这里有另一种解决方案(不使用sort -V
,因为我在使用的任何操作系统中都找不到):
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
)。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/ //;')
sort
版本,不依赖于读取ls
的输出,并且不会遇到管道到while循环的问题。ls
按照非常简单的方式对结果进行排序,因此something-10.whatever
比something-3.whatever
要小。0
)。sort -n
命令。它可以按照数字顺序排序连续的数字块。虽然 "10a" 仍然在 "1a" 之前,但至少 "1-a" 在 "10-a" 之前。 - Ben像@Kusalananda的解决方案(可能更容易记住?)但适用于所有文件(?):
array=("$(ls |sed 's/[^0-9]*\([0-9]*\)\..*/\1 &/'| sort -n | sed 's/^[^ ]* //')")
for x in "${array[@]}";do echo "$x";done
本质上添加排序键,排序,删除排序键。
编辑:将评论移动到适当的解决方案
ls -v
是“强制未编辑的打印非图形字符;当输出不到终端时,这是默认设置。” 在OpenBSD上,它不存在。 - Kusalanandals -v
。 - Kusalananda使用 sort -rh 和 while 循环
du -sh * | sort -rh | grep -P "avi$" |awk '{print $2}' | while read f; do fp=`pwd`/$f; echo $fp; done;