如何从文件名中删除问号和其余部分?
How to remove question mark and the rest from file names?
我使用 wget 抓取了整个网站模板。它在不同的子目录中创建了许多资产文件,其中文件名包含问号,例如 ./fonts/fontawesome-webfont.woff?v=4.5.0
。我需要从这些文件名中截断 ?
和其余部分。我试过这个命令:
find . -type f -name '*\?*' -exec mv "{}" "$(echo {} | sed 's/\?.*//g')" \;
但是不行;什么都不是 replaced/removed,它显示此错误:
mv: './fonts/fontawesome-webfont.woff?v=4.5.0' and './fonts/fontawesome-webfont.woff?v=4.5.0' are the same file
我在不同的目录中有这些类型的文件名,所以我尝试了 find
命令。我在这里错过了什么?
编辑
find . -name '*\?*' -type f -exec sh -c 'for fp; do echo mv -- "$fp" $(printf "%s" "$fp" | sed "s,?[^/]*$,,"); done' sh {} +
## or
find . -name '*\?*' -type f -exec sh -c 'for fp; do echo mv "$fp" $(echo "$fp" | sed "s,?[^/]*$,,"); done' sh {} +
find
命令从当前文件夹 (.
),一旦找到文件,就会执行 sh
脚本。该脚本是 for fp; do echo mv -- "$fp" $(printf "%s" "$fp" | sed "s,?[^/]*$,,"); done
,它遍历找到的文件路径 (fp
),并移动(重命名)具有相同文件路径的文件路径,但不包含以第一个 ?
字符开头的部分文件路径。
sed "s,?[^/]*$,,"
命令实际上找到了一个 ?
,然后是除 /
之外的任意数量的字符,直到字符串结尾,并从文件路径中删除这部分(所以,它只删除文件名的一部分,文件夹名可以包含 ?
个字符)。
如果文件路径以 -
字符开头,mv
之后的 --
是必需的。
注意:从上面的命令中删除 echo
以实际重命名文件。
Linux 18.04 测试解决方案 perl-rename
你可以使用
find . -depth -type f -exec rename -n -v 's/\?.*//' {} +
检查结果,如果它们符合预期,请删除用于“干”的 -n
运行,只检查命令的工作情况。这里,-v
(“verbose”选项)用于打印重命名成功的文件名。
您可以阅读有关如何安装和使用此 rename
command here 的信息。
请考虑find
命令
如 sed
在 find
找到文件之前被调用。我们可以使用 -exec bash -c
解决这个问题,并将路径名 ({}
) 作为参数传递:
find . -type f -exec bash -c 'echo mv [=10=] $(sed "s/\?.*//g" <<< [=10=])' "{}" \;
如果每个文件的输出似乎都找到了,请删除 mv
文件的 echo
前缀:
find . -type f -exec bash -c 'mv [=11=] $(sed "s/\?.*//g" <<< [=11=])' "{}" \;
我本地机器上的小例子:
$ ls -lt
total 0
-rw-r--r-- 1 me wheel 0 Jun 3 17:32 'something.exe?v=23456'
-rw-r--r-- 1 me wheel 0 Jun 3 17:32 'myrandom_file?x=123'
-rw-r--r-- 1 me wheel 0 Jun 3 17:32 'fontaweietsanderssome-webfont.woff?v=4.5.0'
$
$ find . -type f -exec bash -c 'mv [=12=] $(sed "s/\?.*//g" <<< [=12=])' "{}" \;
$
$ ls -lt
total 0
-rw-r--r-- 1 me wheel 0 Jun 3 17:32 something.exe
-rw-r--r-- 1 me wheel 0 Jun 3 17:32 myrandom_file
-rw-r--r-- 1 me wheel 0 Jun 3 17:32 fontaweietsanderssome-webfont.woff
$
假设 rename
不可用(或者您无法安装它),我可能会选择更直接、更容易 (?) 的 understand/maintain。
假设我在名为 question
的目录下有以下内容:
$ ls -1 question
abc?v=4.5.0
def.txt
ghi.pdf?v=1.4.3
一个想法使用简单的 while
循环和 parameter substitution:
find . -type f -name '*\?*' |
while read -r fname
do
echo mv "${fname}" "${fname//\?*/}"
done
这会生成:
mv ./question/abc?v=4.5.0 ./question/abc
mv ./question/ghi.pdf?v=1.4.3 ./question/ghi.pdf
一旦您对生成的 mv
命令感到满意,就可以删除 echo
以便实际 运行 mv
命令。
这是防弹的。
find . -name '*\?*' -type f -exec sh -c '
for fp; do
fn=${fp##*/}
echo mv "$fp" "${fp%/*}/${fn%%\?*}"
done' sh {} +
上面的循环隔离了每个选定文件的名称(在名为 fn
的变量中),以便能够在不破坏任何内容的情况下删除最左边的问号和其余部分;如果我们改为 ${fp%%\?*}
,我们将无法处理名称中带有问号的目录的内容。虽然如果我们确定每个文件名只包含一个问号,${fp%\?*}
就可以正常工作。
如果输出看起来不错,请删除 echo
。