我有几个目录的文件顺序不正确,因为标题显示在文件编号之前。我想匹配并替换所有文件的末尾,减去扩展名,因此数字位于开头,如下所示。
由此;
A guide to perfect eggs-456704.mp4
Boil an egg-456702.mp4
How to ruin scrambled eggs-456703.mp4
Make green eggs and ham-456701.mp4
Poached eggs-456705.mp4
对此:
456701-Make green eggs and ham.mp4
456702-Boil an egg.mp4
456703-How to ruin scrambled eggs.mp4
456704-A guide to perfect eggs.mp4
456705-Poached eggs.mp4
每个带有空格的文件的标题长度是随机的,数字是“.mp4”扩展名之前的 6 位数字,但标题后面有一个破折号。
答案1
使用find
和Shell (Bash, ksh, ksh93, mksh, zsh) Pattern substitution expansion
。
find * -type f -name "*.mp4" -exec bash -c 'echo mv -v "$1" "${1//[^0-9]}-${1//[\-0-9]}"' _ '{}' \;
我们
${1//[^0-9]}
正在删除除数字之外的所有内容;是//
全局替换语法,而/
is 仅用于数字的第一次出现。然后是破折号/连字符
-
,${1//[\-0-9]}
我们将删除所有属于 a-
或数字的内容(再次假设-
文件名中只有一个和数字部分)。
我们-exec
在上面使用的命令由于某些原因不安全1,2在这里,因为使用 Shell Substitution Expansion 它将采用文件的路径并导致意外的重命名+它将删除-
文件名中的所有破折号!
最后,不要忘记删除echo
命令中的上述内容,以在用于空运行的位置进行实际重命名。
find . -type f -name "*.mp4" -execdir sh -c '
n="${1##*-}";fn="${1%-*}";
echo mv -v "$1" "${n%.*}-${fn##*/}.mp4" ' _ '{}' \;
与之前的命令相同,但这里我们使用shell (POSIX sh/bash/Korn/zsh) parameter substitution expansion
这将使-
文件名中的所有破折号保持不变(如果有的话),a file-with -- here-006.file
除了最后一个应该删除的破折号。
我们正在寻找仅以和-type f
结尾的文件,即将当前目录更改为.mp4
-execdir
find
文件找到然后在该目录本身内执行 sh -c ' ... ' 。
使用
n="${1##*-}"
“cut-up-to-last-prefix”:我们删除从文件名开始到最后看到的破折号-
及其-
本身的所有内容,并将其分配给变量n
; or$1
是返回到当前目录${1}
的相对路径。./fileName
-execdir sh -c '...' _ '{}' \;
使用
fn="${1%-*}"
“cut-up-to-first-suffix”:我们将从文件名末尾删除所有内容,直到-
看到第一个破折号及其-
本身,并将其分配给变量fn
。现在
n="456704.mp4"
(nf="./A guide to perfect eggs"
假设第一个文件)。然后;我们将从
${n%.*}-
fileName 末尾删除所有内容,直到.
看到第一个点及其.
本身,然后添加破折号-
。所以这只会产生 fileName 的数字部分456704
。我们
${fn##*/}.mp4
正在删除从文件名的请求到/
看到最后一个斜杠及其/
本身的所有内容,然后添加.mp4
到末尾。所以才会出现这样的结果A guide to perfect eggs.mp4
。
1 使用中存在哪些安全问题和竞争条件find -exec
?
2 为什么使用“-execdir”操作对于 PATH 中的目录不安全?
答案2
这里有一种方法可以做到这一点。未经测试
#!/bin/bash
files=(*file)
for f in "${files[@]}"
do
get_ext="${f##*.}"
no_ext="${f%-*}"
n="${f##*-}" nn="${n%.*}"
mv "$f" "$nn-$no_ext.$get_ext"
done
答案3
set "a file blah blah-004.file" \
"b file blah blah blah-002.file" \
"c file blahh blah-003.file" \
"d file blah blah blah blabby blah-001.file" \
"e file blah-005.file"
for name; do
old=$name # save old name
ext=${name##*.} # take extension
name=${name%.*} # remove extension
number=${name##*-} # take number
name=${name%-*} # remove number
new="$number-$name.$ext" # set new name
echo mv "$old" "$new" # test rename
done
echo
如果有效的话,删除最后一个。
答案4
这是一个可移植的sh
实现。
find . -name "*[0-9].mp4" |
sed "s/\(.*\/\)\(.*\)-\([0-9]*\)\.mp4/'\1\2-\3.mp4' '\1\3-\2.mp4'/" |
xargs -p -L 1 mv -v
该find
命令非常简单:它将仅返回.mp4
扩展名前至少包含一位数字的文件。
该sed
命令复制文件名,用单引号将每个文件名引起来,然后第二个文件名将数字部分相应地在相对文件路径和文件名之间移动(例如,'./a/Boil an egg-456707' './a/456707-Boil an egg.mp4'
)。
然后将生成的当前文件名和新文件名列表传递给xargs
命令,该命令将执行mv -v
.-L 1
需要该选项以便xarg
一次处理一行。您可以-p
从此命令中删除该选项并更改应使用的选项mv
。
我在 Ubuntu bash
、 Mac OS High Sierra和sh
Mac OS High Sierra上使用您的文件列表测试了此实现,将文件放置在不同的子目录中并添加了一些不合格的文件。bash
sh