如何将许多文件url转义(%XX)重命名为人类可读的形式



已编辑:将国际字符添加为"Séléction",并在文件名中添加引号

我已经在一个目录中下载了很多文件,但其中许多文件都以 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 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
...

所有这些名称都与以下形式匹配,正好由 3 个部分组成:

  • 对象的名称-(修订版和/或日期,无用... ).扩展

在同一个命令中,我想获得 unde

我的目标是有一个命令来重命名所有这些文件以获取:

-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/%(..)/\x1/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'))

为什么不像这样:

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;

使用不同的语法,它变成:

for i in *; do mv "$i" "$(perl -MURI::Escape -e '$u=uri_unescape($ARGV[0]); chomp($u); $u=~s/s/_/g; $u=~s/-(.*)//; print $u;' "$i")"; done;

(我也修复了dobule引号)

编辑:但这要好得多:

rename 's/%([0-9A-Fa-f]{2})/chr(hex($1))/eg|s/s/_/g|s/-(.*)//' *

重命名支持使用正则表达式重命名文件。第一个正则表达式取自这里:http://search.cpan.org/dist/URI/URI/Escape.pm 这正是uri_unescape所做的。然后我们可以使用 | 将更多的正则表达式连接到同一个字符串中。它看起来很干净,我学到了一些新东西:)

这是使用 sed 的快速方法:

for i in *; do mv "$i" "$(echo -e $(echo $i | sed -e 's/-%28.*(..*)/1/' -e 's/%20/_/g' -e 's/%(..)/\x1/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

如果你有 Perl 5.14,

perl -MURI::Escape -e'
   rename $_, uri_unescape($_) =~ s/-(.+)././r =~ tr/ /_/r
      for @ARGV;
' *

为提高可读性而添加了换行符。它们可以被删除。

使用

Perl 的 URI:Escape 模块相对来说,这是相对简单的。不幸的是,它不是核心模块,因此您可能需要安装它。

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 -MURI::Escape -e'
   for (@ARGV) {
      $o = $_;
      $_ = uri_unescape($_);
      s/-(.+)././;
      tr/ /_/;
      rename $o, $_;
   }
' *

是的! @fthiella是第一个提供基于perl软件包中实用程序rename的解决方案!

注意:重命名这个词是第三个,在这个线程的标题中。

apropos rename
...
mv (1)               - move (rename) files
prename (1)          - renames multiple files
rename (1)           - renames multiple files
rename (2)           - change the name or location of a file
rename.ul (1)        - Rename files
...

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/-(.*)././' *

或者(我相信这更好,但我不确定!

rename 'BEGIN{use URI::Escape};$_=uri_unescape($_);y| |_|;s/-(.*)././' *

谢谢大家!

快速(无叉),纯 bash 解决方案

最新版本的bash提供了很多不错的工具。这个版本除了mv工具之外不使用任何分支。

for file in *;do
    printf -v newname "%b" ${file//%/\x}
    mv "$file" "$newname"
done

好的,这并不完美,因为没有正确测试两个跟随百分号的caracter,但是对于正确的url转义字符串,这将正常工作。

cd Downloads
for i in *; do res=$( echo $i | sed 's/%[0-9][0-9]/_/g' ); mv $i $res; done 

相关内容

  • 没有找到相关文章

最新更新