我有一个简单的字符串,它将按顺序重命名文件夹中的所有 jpeg 文件:
ls -v | cat -n | while read n f; do mv -n "$f" "pic-$n.jpg"; done
但是我有一个包含多种不同文件类型的文件夹。是否有一个简单的字符串或变量可以替换.jpg
以保留文件扩展名?还是现在必须是一个完整的脚本?如果可能的话,我想将其保留为一行。
例子
假设我有一个这样的文件夹:
a long hash name.mp4
another name.m4v
video.mov
another name.mp4
等等。我想像下面这样重命名文件,以便它们看起来更有条理,并且没有太多字符,就像这样:
vid-1.mp4
vid-2.m4v
vid-3.mov
vid-4.mp4
如果我要使用ls -v | cat -n | while read n f; do mv -n "$f" "vid-$n"; done
,那么我就不会有文件扩展名。我想保留文件扩展名,因为这样有时可以更轻松地打开它们。
我主要想知道 bash 中是否有一个全局变量来定义文件扩展名
答案1
这里不要使用循环,只需使用rename
:
$ ls
'a bad name.png' asdlha.gif askd.png 'a worse'$'\n''name.jpg' kasdjh.jpg
$ rename -n 's/.*(\..+)/"pic-" . ++$a . "$1"/se' *
a bad name.png -> pic0.png
asdlha.gif -> pic1.gif
askd.png -> pic2.png
a worse
name.jpg -> pic3.jpg
kasdjh.jpg -> pic4.jpg
如果看起来正确,则重新运行但不-n
进行实际重命名。
解释:
该rename
命令是一个 perl 脚本,可以运行 perl 代码来重命名文件。在这里,我们使用替换运算符 ( s/old/new/
) 和几个特殊选项:
- 这
/s
使得替换运算符将其输入视为一行,从而允许.
匹配换行符。我们需要它来处理带有换行符的文件名,就像我在上面的例子中所做的那样。 - 让
/e
我们将右侧 (s/left/right/
) 评估为 perl 表达式。表达式的"pic-" . ++$a . "$1"
意思是“字符串pic-
,然后是变量的值$a
增加一,然后是左侧括号内匹配的内容”。在我们的例子中,是扩展。
接下来,使用的正则表达式 ( .*(\..+)
) 表示“零个或多个字符 ( .*
) 直到最后一个.
(\.
匹配文字.
),然后是一个或多个字符 ( .+
)。因为最后一个\..+
在括号中,所以匹配的内容(扩展名)可以$1
在右侧找到。
运行上述不带 的命令后-n
,剩下:
$ rename 's/.*(\..+)/"pic-" . ++$a . "$1"/se' *
terdon@oregano foo $ ls
pic-1.png pic-2.gif pic-3.png pic-4.jpg pic-5.jpg
或者,你可以在 shell 中使用以下命令执行此操作:
i=1; for file in *; do
ext="${file##*.}";
mv -- "$file" pic-$((i++))."$ext";
done
在这里,我们循环遍历所有文件(和目录,如果你不想重命名目录,请小心),将每个文件另存为$file
。然后,我们用 获得扩展名${file##*.}
。格式将从变量 中${variable##pattern}
删除最长的匹配项。通过使用,我们删除所有内容直到最后一个,只留下我们另存为 的扩展名。pattern
$variable
${file##*.}
.
$ext
接下来,该mv
命令将重命名$file
为,加上我们用初始化的pic-
变量的值,加一,然后是 a和扩展名。$i
i=1
.
与上面的解决方案类似rename
,这也可以处理任意文件名:
$ ls
'a bad name.png' asdlha.gif askd.png 'a worse'$'\n''name.jpg' kasdjh.jpg
$ i=1; for file in *; do
ext="${file##*.}";
mv -- "$file" pic-$((i++))."$ext";
done
$ ls
pic-1.png pic-2.gif pic-3.png pic-4.jpg pic-5.jpg
答案2
如果你特别需要文件以算术方式命名版本排序顺序(与ls -v
)那么我建议
printf '%s\0' *.* | sort -zV | {
local n=1
while IFS= read -r -d '' f; do
echo mv -nv -- "$f" "pic-$((++n)).${f##*.}"
done
}
或者,如果你想用零填充新名称(这会使后续排序更容易),也许
printf '%s\0' *.* | sort -zV | {
local n=1
while IFS= read -r -d '' f; do
printf -v p 'pic-%03d.%s' $((++n)) "${f##*.}"
echo mv -nv -- "$f" "$p"
done
}
echo
确认正确的文件将按照所需顺序处理后,删除。如果您不关心可读性,当然可以将它们写成“一行”,例如
printf '%s\0' *.* | sort -zV | { local n=1; while IFS= read -r -d '' f; do printf -v p 'pic-%03d.%s' $((++n)) "${f##*.}"; echo mv -nv -- "$f" "$p"; done; }