我有一组文件(列表较大,4x43文件扩展名为I.sto,Q.sto,U.sto和V.sto):
probni45069Q.sto probni45080I.sto probni45080V.sto probni45083U.sto
probni45069U.sto probni45080Q.sto probni45083I.sto probni45083V.sto
probni45069I.sto probni45069V.sto probni45080U.sto probni45083Q.sto
我的目标是按照从数字1开始的排序顺序重命名它们:
我已按照Renaming files in a folder to sequential numbers的说明和指南创建了以下bash脚本:
model='probni'
for sto in I Q U V;
do
i=1
for j in $model*$sto.sto;
do
echo "$j" `printf $model%1d$sto.sto $i`
mv "$j" `printf $model%1d$sto.sto $i` 2>/dev/null || true
i=$((i + 1))
done
done
此脚本仅在使用一次时效果很好。问题是当我在已经排序的文件集上多次使用它时,或者当我有一组已排序的文件以及其他未排序的文件(例如probni1I.sto + probni1346I.sto)时,我丢失了一定数量的文件。在我原来的4x43文件集上重复使用时,我最终以4x7文件集结束。
我的问题是如何使这个脚本对于排序文件是幂等的,或者如何只是将新的未排序文件添加到排序列表而不丢失任何文件。
答案 0 :(得分:2)
问题是文件名是按字典顺序排序的,这会导致数字出现问题,因为1 2 1346
将排序为1 1346 2
,因为字符1
位于2
之前。您需要更智能的排序,更直观地处理数字。
sort -g
正是医生所要求的。通过sort -g
和1346
过滤您的文件列表不会给您带来更多麻烦。
for j in $(ls $model*$sto.sto | sort -g); do
...
done
通常parsing the output of ls is a bad idea。如果你想做的事情非常正确,你需要重新构建一些事情。
for sto in I Q U V; do
find -maxdepth 1 -name "$model*$sto.sto" -print0 |
sort --files0-from - -z |
{
i=1
while IFS= read -rd $'\0' old; do
new=$model$i$sto.sto
[[ $old == $new ]] && continue
echo "$old" "$new"
mv -- "$old" "$new" 2>/dev/null || true
((i++))
done
}
done
这是一项很多工作,但是这个版本处理奇怪的文件名要好得多。它在所有阶段都使用NUL分隔符,因此带有空格和换行符的文件名不会对作品产生影响。
我不希望你有这样奇怪的文件,但是嘿,比抱歉更安全。尝试做正确的事情总是好的。
答案 1 :(得分:0)
只要目标文件已存在,如何在循环中递增i?
while [ ! -f FILENAME ]
do
INCREMENT
done
编辑:我错过了你的输入和输出文件看起来一样。这将要求你要么1)改变其中任何一个的命名方案,2)将它们放在不同的目录中,或者3)在你从1开始计算间隙时开始重命名
答案 2 :(得分:0)
通常解析ls
的输出被认为是错误的。但是,如果文件夹仅包含显示模式后面的文件,则可以使用以下shell脚本:
ls | sort -k1.12 -k2.6n | awk '{
n=substr($0,7,5);
l=substr($0,12,1);
c[l]++;
system("mv "$0" probni"c[l]""l".sto")
}'
sort -k1.12 -k2.6n
将按照末尾的字母和中间的数字对文件进行排序。这只适用于文件名长度相同且数字总是5个字符长,前缀总是probni
(长6个字符)。
管道末尾的awk脚本使用substr()
反汇编文件名,并按照所需模式重新组装。 system()
用于发出mv
命令。