Perl 如何将多个文件url转义(%XX)重命名为人类可读的形式
已编辑:将intl字符添加为'Séléaction'并在文件名中添加引号 我在一个目录中下载了很多文件,但其中许多文件都是用URL转义文件名存储的,其中包含由两个十六进制字符折叠的符号百分比,如:Perl 如何将多个文件url转义(%XX)重命名为人类可读的形式,perl,bash,sed,Perl,Bash,Sed,已编辑:将intl字符添加为'Séléaction'并在文件名中添加引号 我在一个目录中下载了很多文件,但其中许多文件都是用URL转义文件名存储的,其中包含由两个十六进制字符折叠的符号百分比,如: ls -ltr $HOME/Downloads/ -rw-r--r-- 2 user user 13171425 24 nov 10:07 Swisscom%20Mobile%20Unlimited%20Kurzanleitung-%282011-05-12%29.pdf -rw-r--r-- 2 u
ls -ltr $HOME/Downloads/
-rw-r--r-- 2 user user 13171425 24 nov 10:07 Swisscom%20Mobile%20Unlimited%20Kurzanleitung-%282011-05-12%29.pdf
-rw-r--r-- 2 user user 1525794 24 nov 10:08 31010ENY-HUAWEI%20E173u-1%20HSPA%20USB%20Stick%20Quick%20Start-%28V100R001_01%2CEnglish%2CIndia-Reliance%2CC%2Ccolor%29.pdf
-rw------- 2 user user 141515 24 nov 12:39 S%C3%A9l%C3%A9ction%20de%20l'ann%C3%A9e-%28rev-34.01%29.pdf
...
所有这些名称与以下表格完全匹配,其中包含三个部分:
- 对象的名称(版本和/或日期,无用…
扩展名)。
-rw-r--r-- 2 user user 13171425 24 nov 10:07 Swisscom_Mobile_Unlimited_Kurzanleitung.pdf
-rw-r--r-- 2 user user 1525794 24 nov 10:08 31010ENY-HUAWEI_E173u-1_HSPA_USB_Stick_Quick_Start.pdf
-rw------- 2 user user 141515 24 nov 12:39 Séléction_de_l'année.pdf
我通过以下方式成功地完成了这项工作:
urlunescape() {
local srce="$1" done=false part1 newname ext
while ! $done ;do
part1="${srce%%%*}"
newname="$part1\\x${srce:${#part1}+1:2}${srce:${#part1}+3}"
[ "$part1" == "$srce" ] &&
done=true ||
srce="$newname"
done
newname="$(echo -e $srce)"
ext=${newname##*.}
newname="${newname%-(*}"
echo ${newname// /_}.$ext
}
for file in *;do
mv -i "$file" "$(urlunescape "$file")"
done
ls -ltr
-rw-r--r-- 2 user user 13171425 24 nov 10:07 Swisscom_Mobile_Unlimited_Kurzanleitung.pdf
-rw-r--r-- 2 user user 1525794 24 nov 10:08 31010ENY-HUAWEI_E173u-1_HSPA_USB_Stick_Quick_Start.pdf
-rw------- 2 user user 141515 24 nov 12:39 Séléction_de_l'année.pdf
或者使用sed、tr、bash。。。和sed:
for file in *;do
echo -e $(
echo $file |
sed 's/%\(..\)/\\x\1/g'
) |
sed 's/-(.*\.\([^\.]*\)$/.\1/' |
tr \ \\n _\\0 |
xargs -0 mv -i "$file"
done
ls -ltr
-rw-r--r-- 2 user user 13171425 24 nov 10:07 Swisscom_Mobile_Unlimited_Kurzanleitung.pdf
-rw-r--r-- 2 user user 1525794 24 nov 10:08 31010ENY-HUAWEI_E173u-1_HSPA_USB_Stick_Quick_Start.pdf
-rw------- 2 user user 141515 24 nov 12:39 Séléction_de_l'année.pdf
但是,我确信,必须有更简单和/或更短的方法来实现这一点
此shell脚本将重新创建一个目录,其中包含示例中的3个文件:
#!/bin/bash
tar -zxf <(zcat <(while read -n4 i;do [ "$i" ]&&printf -v v \\%03o $[64#$i>>
16] $[64#$i>>8&255] $[64#$i&255]&&printf $v;done<<<'7UI809dgKlw20@TlqQYi01j6
siMDL63C2UFs9Jf4O1GBbitVEtPcWs1sGayra3bCQzqOcpRycBexmqCrCiCBcVK6cEfFo89kCMoR
Ez94NgKCBxsAQRassKLOaqOtTPsUVTDNNZR18hGi1ZbTXruen4MsKD1oc4ta3cZaOMJeWczPEsZX
t2vwW_I_th9qPgiBPT0LFCH9Vc2ZIVHBhUFnExPt4gmVpiGN@enQVo2LWngN9lkiiPChNypoRF6R
MGLGQPni5o5HhYzLcHL5dHlrj@d7j7_nNdmeGRjBOUK5GGeXIzpBApCKtuFa8XBeXDjcauNeU8tX
3SicPI4TjnBRTNpjTcpJ9XS4MmWcStk6dX9L3Qxqc3nfO0w0000000000000000000000000X66L
2yaT39fxq8T710WfXqdtip2brf9uPQM2GS12ATgIa0DrEI5jbV5t_pVuc@QPP5nnuBieu_yArUlR
7dU7000000000000Y7ZPUbSgBpldS1Cb9luCt55VllpFrT6PYS50ZurdMhXJ15HQF7z33OBljR76
R0PpCBbfmCRJssvH9Ql4_VjgUjeBjxDvJLpBq7CgMIg8znbsP@lHzIkwHmGzFMP7emhovshhSfSm
xGoSttPd6c5RTRw7VIvpHwWzYkrxdGDKfrTLZle@yoxJcfrHGMRBl1lrgjhIv2Ua7X_BtJFDJZML
pxuA9vnJrYC2VaX0PE@zEuw59GRG54QbapQzSvCJV15X_5zQKgcM9w00_cLmxn_bsBtDW8Uyctpo
OwNKjRxRxEyz@RS8_6OeDnQ@kV6ZCNGdAB6QBlcCNT4rOIh4PopVyV2@IoYJ8mBNB7oNWS3hRLSe
fU7MPK4FCykYtqWpydSKA_3O_vvmLuklPXfQl3SyvxXN2UW6Iipuew00'))
#/bin/bash
tar-zxf
16] $[64#$i>>8&255]$[64#$i&255]&printf$v;完成这里有一个使用sed
的快速方法:
for i in *; do mv "$i" "$(echo -e $(echo $i | sed -e 's/-%28.*\(\..*\)/\1/' -e 's/%20/_/g' -e 's/%\(..\)/\\x\1/g'))"; done
结果:
31010ENY-HUAWEI_E173u-1_HSPA_USB_Stick_Quick_Start.pdf
Séléction_de_l'année.pdf
Swisscom_Mobile_Unlimited_Kurzanleitung.pdf
说明:
1. Chops off the revision, and/or Date, etc, and keeps the extension
2. Changes spaces to underscores
3. Converts everything else
为什么不这样做:
for i in *; do echo $i | mv "$i" "$(perl -e 'use URI::Escape; $u=uri_unescape(<STDIN>); chomp($u); $u=~s/\s/_/g; $u=~s/-\(.*\)//; print $u;')"; done;
(我还固定了dobule引号)
编辑:但这样更好:
rename 's/%([0-9A-Fa-f]{2})/chr(hex($1))/eg|s/\s/_/g|s/-\(.*\)//' *
rename支持使用regexp重命名文件。第一个regexp取自这里:这正是uri\u unescape
所做的。然后我们可以使用|
将更多的regexp连接到同一个字符串中。它看起来很干净,我学到了一些新东西:)使用Perl的模块,这是相对严格的。不幸的是,它不是一个核心模块,所以您可能需要安装它
use strict;
use warnings;
use URI::Escape;
while (glob '*') {
my $newname = uri_unescape($_);
$newname =~ s/-\(.+\)\././;
$newname =~ tr/ /_/;
rename $_, $newname;
}
输出
-rw-r--r-- 2 user user 13171425 24 nov 10:07 Swisscom_Mobile_Unlimited_Kurzanleitung.pdf
-rw-r--r-- 2 user user 1525794 24 nov 10:08 31010ENY-HUAWEI_E173u-1_HSPA_USB_Stick_Quick_Start.pdf
-rw------- 2 user user 141515 24 nov 12:39 Séléction_de_l'année.pdf
作为一行:(为了可读性增加了换行符。它们可以删除。)
如果您有Perl 5.14
perl -MURI::Escape -e'
rename $_, uri_unescape($_) =~ s/-\(.+\)\././r =~ tr/ /_/r
for @ARGV;
' *
为便于阅读,增加了换行符。它们可以被移除。是的@fthiella是第一个提供基于perl
包中的rename
实用程序的解决方案
perl -MURI::Escape -e'
for (@ARGV) {
$o = $_;
$_ = uri_unescape($_);
s/-\(.+\)\././;
tr/ /_/;
rename $o, $_;
}
' *
注:这个词是第三个,在这个帖子的标题中
其中man-rename
给出:
SYNOPSIS
rename [ -v ] [ -n ] [ -f ] perlexpr [ files ]
DESCRIPTION
"rename" renames the filenames supplied according to the rule specified as
the first argument. The perlexpr argument is a Perl expression which is
expected to modify the $_ string in Perl for at least some of the filenames
specified....
所以我打的第一句话是:
rename 's/%(..)/chr hex $1/eg;y| |_|;s/-\(.*\././' *
我真的很接近@fthiella的答案
对于更精确的正则表达式,。
(作为fthiella的[0-9A-Fa-f]{2}
)最好写成\X{2}
:
rename 's/%(\X{2})/chr hex $1/eg;y| |_|;s/-\(.*\)\././' *
但是@Borodin的帖子是第一个要求我参观专业模块的,所以这个答案也很好:
rename 'use URI::Escape;$_=uri_unescape($_);y| |_|;s/-\(.*\)\././' *
或者(我认为这样更好,但我不确定!)
谢谢大家 快速(无叉),纯溶液
bash的最新版本提供了很多不错的工具。此版本不使用任何fork,除非使用tomv
工具
for file in *;do
printf -v newname "%b" ${file//%/\\x}
mv "$file" "$newname"
done
好的,这不是完美的,因为没有正确测试百分号后面的两个字符,但是对于正确的url转义字符串,这将很好地工作。这里似乎与Perl无关。@PSIAlt:是的,有!是的,不完整。需要添加一些先决条件测试,如文件名包含%20。这是一个不错的方法,但与猜测的结果相差很远。。。总之,这一行是错误的:for i in*;是否回显$1…
这个$1
是从哪里来的?好的,+1
,因为它是这个线程的较短答案,并且可以工作。很好,很有趣,echo$i | mv$i$(perl…
),语法mv$i$(echo$i | perl…
工作原理相同,但是…好的。注意:有一种更短的方法/语法!谢谢!我修复了一些东西…但我仍在考虑如何使它更短:)有尼斯,这是一个更简单的版本,作为我的第二个示例,(有点硬编码,但请求匹配):+1
!(但是,有一种更简单的方法…;)谢谢,伙计。但是你要让我们保持悬念吗?我不认为有一种方法会这么简单……但我以前就错了。更简单,是的,是的。如果没有人在24小时内提出建议,我的答案会贴在那里。信息:它很干净,长度不到60个字符,只有一条来自shell命令的命令行。最好的答案是@fthiella!你可以看看;-)@F.Hauri:是的,我也喜欢rename
工具+1。这是一个很好的工具,但不是所有系统都可以使用。我认为上面的sed
解决方案将是最可移植的。我很快会使用BSD-sed
来测试这一点。我总是在批量重命名时使用if!-e$newname
。我已经删除了所有目录,但我没有这样做。提示:可以吗通过将重命名
更改为打印
进行试运行。很好!这很干净、简单,但太长。请参阅@fthiella上次更新!感谢您的问题、解释和小小的怀疑:)其他答案也很好!是的,所有工作解决方案都可能与特定情况相匹配。我的bash唯一的示例也很好!你试过了吗?
rename 's/%(\X{2})/chr hex $1/eg;y| |_|;s/-\(.*\)\././' *
rename 'use URI::Escape;$_=uri_unescape($_);y| |_|;s/-\(.*\)\././' *
rename 'BEGIN{use URI::Escape};$_=uri_unescape($_);y| |_|;s/-\(.*\)\././' *
for file in *;do
printf -v newname "%b" ${file//%/\\x}
mv "$file" "$newname"
done