2

編集: intlcharsを`Séléction'として追加し、ファイル名に引用符を追加します

1つのディレクトリに多くのファイルをダウンロードしましたが、それらの多くはURLでエスケープされたファイル名で保存され、次のように2つの16進文字が続く符号パーセントが含まれています。

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を取得したい

私の目標は、このすべてのファイルの名前を変更して取得するコマンドを1つ持つことです。

-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

私は次のように完全にbashで仕事を成功させました:

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

しかし、私は確信しています、これを行うためのより単純なおよび/またはより短い方法が存在する必要があります。

このシェルスクリプトは、サンプルから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'))
4

7 に答える 7

3

なぜこのようなものではないのですか?

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;

(そして私は二重引用符も修正しました)

編集:しかし、これははるかに優れています:

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

renameは、regexpを使用したファイルの名前変更をサポートします。最初の正規表現はここから取得されます:http ://search.cpan.org/dist/URI/URI/Escape.pmそしてそれはまさにそれがuri_unescape行うことです。次に、を使用して同じ文字列でより多くの正規表現を結合できます|。それはきれいに見え、私は何か新しいことを学びました:)

于 2012-11-24T14:34:52.583 に答える
2

これを使用する簡単な方法は次の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
于 2012-11-24T11:46:08.623 に答える
2

Perl 5.14を使用している場合、

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

読みやすくするために改行が追加されました。それらは削除することができます。

于 2012-11-24T16:47:03.003 に答える
2

はい!@fthiellaは、パッケージのrenameユーティリティに基づいたソリューションを最初に提供しました。perl

注:名前の変更という単語 は、このスレッドのタイトルの3番目です。;-)

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の答えに本当に近いです!

より正確な正規表現については、..[0-9A-Fa-f]{2}fthiellaの時点で)次のように記述した方がよいでしょう\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/-\(.*\)\././' *

皆さんありがとう!

于 2012-11-24T17:49:25.993 に答える
1

これは、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, $_;
   }
' *
于 2012-11-24T14:37:12.260 に答える
0

高速(フォークなし)、純粋なソリューション

最近のバージョンのbashは、多くの優れたツールを提供します。mvこのバージョンでは、ツール以外のフォークは使用していません。

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

パーセント記号に続く2つの文字を正しくテストしていないため、これは完全ではありませんが、正しいURLエスケープ文字列の場合、これは正常に機能します。

于 2017-03-03T10:53:21.493 に答える
-2
cd Downloads
for i in *; do res=$( echo $i | sed 's/%[0-9][0-9]/_/g' ); mv $i $res; done 
于 2012-11-24T10:55:39.500 に答える