2013-10-16 32 views
0

我的Linux系統掛載了一些Samba共享,並且一些文件由Windows用戶存放。這些文件的名稱有時包含空格和其他不受歡迎的字符。將這些字符更改爲連字符-似乎是一個合理的解決方案。沒有其他需要更改來處理這些清理的文件名稱。Perl腳本使用名稱中的空格重命名文件,pushd/popd等效於?

幾個問題,

  • 什麼其他字符,除了空格,括號應該翻譯?

  • 應該檢查其他文件屬性(除了文件類型(文件/目錄)和權限)?

  • Perl是否提供了一個pushd/popd等效,或者是chdir合理的解決方案來遍歷目錄樹?

這是我的Perl程序

#!/bin/env perl 
use strict; 
use warnings; 

use File::Copy; 

#rename files, map characters (not allowed) to allowed characters 
#map [\s\(\)] to "-" 

my $verbose = 2; 
my $pat  = "[\\s\\(\\)]"; 

sub clean { 
    my ($name) = @_; 
    my $name2 = $name; 
    $name2 =~ s/$pat/\-/g; 

    #skip when unchanged, collision 
    return $name if (($name eq $name2) || -e $name2); #skip collisions 

    print "r: $name\n" if ($verbose > 2); 
    rename($name, $name2); 

    $name2; 
} 

sub pDir { 
    my ($obj) = @_; 
    return    if (!-d $obj); 
    return    if (!opendir(DIR, $obj)); 

    print "p: $obj/\n" if ($verbose > 2); 
    chdir($obj); 

    foreach my $dir (readdir DIR) { 
    next if ($dir =~ /^\.\.?$/); #skip ./, ../ 
    pDir(clean($dir)); 
    } 
    close(DIR); 
    chdir(".."); 
} 

sub main { 
    foreach my $argv (@ARGV) { 
    print "$argv/\n" if ($verbose > 3); 
    $argv = clean($argv); 
    if (-d $argv) { pDir($argv); } 
    } 
} 

&main(); 

這些職位有關係,但不真正解決我的問題,

+5

你有什麼*「其他原因」*不要使用'File :: Find'?它非常適合此目的,並且是核心模塊,因此不需要安裝。 – Borodin

+0

從子程序中刪除了主導符號,使用內置重命名 – ChuckCottrill

回答

3

這裏有一個不同方式來思考問題:

  1. Perl有一個內置的rename函數上。你應該使用它。

  2. 創建一個映射舊名稱到新名稱的數據結構。擁有這些數據將允許進行各種合理性檢查:例如,您不想讓已清除的名字跺跺現有文件。

  3. 由於您沒有遞歸處理目錄,因此可以使用glob來獲得更好的優勢。無需通過打開目錄,讀取它們,篩選點目錄等的麻煩。

  4. 不要調用具有主導符號的子例程(有關更多詳細信息,請搜索此問題)。

  5. 許多類Unix系統都包含一個基於Perl的rename命令,用於快速重命名作業。即使您沒有將它用於當前項目,也很高興知道。

這裏有一個大致的輪廓:

use strict; 
use warnings; 

sub main { 
    # Map the input arguments to oldname-newname pairs. 
    my @renamings = 
     map { [$_, cleaned($_)] } 
     map { -f $_ ? $_ : glob("$_/*") } 
     @_; 

    # Sanity checks first. 
    # - New names should be unique. 
    # - New should not already exist. 
    # - ... 

    # Then rename. 
    for my $rnm (@renamings){ 
     my ($old, $new) = @$rnm; 
     rename($old, $new) unless $new eq $old; 
    } 
} 

sub cleaned { 
    # Allowed characters: word characters, hyphens, periods, slashes. 
    # Adjust as needed. 
    my $f = shift; 
    $f =~ s/[^\w\-\.\/]/-/g; 
    return $f; 
} 

main(@ARGV); 
+0

非常好的代碼。仍然:(1)錯誤檢查'重命名'聽起來像一個好主意。 (2)我很驚訝你有反斜槓,但沒有時間作爲允許的字符:雖然Windows文件名永遠不會包含反斜槓,但這個字符在bash中仍然非常不方便。 – amon

0

不要爲你的問題歸咎於Windows操作系統。 Linux更加鬆懈,而它的文件名中禁止的唯一字符是NUL。

目前尚不清楚你在問什麼。你是否發佈了批評的代碼,或者你有問題嗎?

至於你問的具體問題,

  • 什麼其他字符,除了空格,括號應該翻譯?

    Windows允許任何字符在其文件名中,除了控制字符從0x00到0x1F的,在任何0x7F的的

    < > \/* ? |

    DEL是罰款。

    在ASCII字符集,留下

    ! # $ % & ' () + , - . : ; = @ [ ]^_ ` { } ~

    設定您需要翻譯的字符取決於你的理由這樣做。您可能希望排除非ASCII字符開始,因此您的代碼應改爲類似

    $name2 =~ tr/\x21-\x7E/-/c

    這將改變所有非ASCII字符,空格和DEL來連字符。然後,您需要繼續並修復您認爲不可取的所有ASCII字符

  • 應該檢查其他文件屬性(除了文件類型(文件/目錄)和權限)?

    根據您的目的的答案必須是。如果您只是提及重命名文件或目錄是否爲可能,那麼我建議您讓rename本身告訴您它是否成功。如果操作失敗,將返回一個值,原因將在$!

  • Perl提供pushd/popd等價物,還是chdir是遍歷目錄樹的合理解決方案?

    如果你想與成語來工作,那麼你應該看看File::pushd,它可以讓你暫時chdir到新的位置。 A popd隱含在封閉塊的末尾。

我希望這有助於。如果您有任何其他具體問題,請通過編輯您的原始帖子將其告知。