2012-07-19 63 views
1

我有一堆按以下方式批量重命名的目錄按相反的順序

1 - *random*name*1* 
2 - *random*name*2* 
... 
725 - *random*name*725* 

前置號碼(1-725)命名的目錄名的一部分(超過700)的目錄。

即:所有的目錄名都以數字開頭,後跟[空格] [破折號] [空格],後跟一些文字。

我想批量重命名他們,這樣他們就會被命名爲以下幾點:

1 - *random*name*725* 
2 - *random*name*724* 
... 
725 - *random*name*1* 

我願意「反向」只是目錄名的零件數量。本質上,我希望在「1 - 」之後出現的文字跟隨「725 - 」,在「2 - 」之後出現的文字跟在「724 - 」之後,等等。

最簡單的方法是什麼?我在Linux上。

注意: *隨機*名稱*都是不同的,僅用於說明目的。

+0

是否 「隨機名稱」 立爲*同*名進行的所有725個目錄,或不同的名字? – 2012-07-19 13:04:30

+0

不同的名字 – zigamilek 2012-07-19 13:06:09

+0

你有什麼試過?我將首先查看'os'和'copy'模塊以及列表的'reverse()'方法。 – 2012-07-19 13:08:07

回答

1

單程使用perl。代碼被評論。

內容script.pl

#!/usr/bin/env perl 

use warnings; 
use strict; 
use File::Basename qw|basename|; 

die qq{Usage: perl $0 <real|trial>\n} unless @ARGV == 1; 

my $real = $ARGV[0] eq q|real| ? 1 : 0; 

## Filter filenames from the directory that match criteria of OP. 
my @files = grep { -d $_ && m/\A(\d+)\s-\s.*\1/ } map { basename $_ } <./*>; 

## Get numbers in reverse mode to substitute them later in filenames . 
my @nums = map { m/\A(\d+)/; $1 || 0 } reverse @files; 

## Process all files, change the number of the file and rename it. 
for my $file (@files) { 
    (my $new_file = $file) =~ s/\A(\d+)/shift @nums/e; 

    if ($real) { 
     rename $file, $new_file or warn qq|WARN: Couldn't rename "$file"\n|; 
    } 
    else { 
     printf qq|%s\n|, qq|rename "$file" "$new_file"|; 
    } 
} 

列出目錄:

ls -1 

有了以下的輸出:

1 - file1file 
2 - fi2le 
3 - fileeee3 
4 - fou4r 
5 - donttouch 
6 - donttouch5either 
script.pl 

運行腳本:

perl script.pl 

再次列出directoy:

ls -1 

有了以下的輸出:

1 - fou4r 
2 - fileeee3 
3 - fi2le 
4 - file1file 
5 - donttouch 
6 - donttouch5either 
script.pl 

編輯:有在意見建議,讓之前的真正的試運行,所以我添加了一個參數realtrial。有了第一個選項,它會做出真正的改變,而第二個選項將print輸出真正的命令,但不運行它們。現在運行像腳本:

perl script.pl real 

perl script.pl trial 
+0

謝謝,我們正在某處。我認爲你去了更多的併發症。請注意,所有目錄名都以數字開頭,後跟[空格] [破折號] [空格],接着是一些我不想修改的文本**(即使它包含數字)。我想從你的例子中看到的結果是'1 - fou4r,2 - fileeee3,3 - fi2le,4 - file1file'。對不起,Perl對我來說就像是廢話,所以我不能自己修改你的代碼。 – zigamilek 2012-07-19 13:54:16

+0

@zigamilek:固定。 – Birei 2012-07-19 14:02:09

+0

謝謝!我已經在測試目錄中測試過,並且它可以工作。有沒有辦法先對實際目錄進行「試運行」而不作任何改動?正如你會在實際做「mv」之前在控制檯中「回顯mv」一樣? – zigamilek 2012-07-19 14:12:21

0

如果這AWK解決你合適嗎?

CMD:

ls -F|grep "/$"|sort|awk 'BEGIN{FS=" - ";l=5;}{o=$0;gsub("/$","",o);gsub($1"/$",l--);if(o!=$0)printf "mv \"%s\" \"%s\"\n",o,$0 }' |sh 

這裏的5是硬編碼,你的情況是725 :)當然,它可以通過廁所-l設置,但我升技懶惰。

測試:

kent$ tree -d 
. 
|-- 1 - foo1 
|-- 2 - foo2 
|-- 3 - foo3 
|-- 4 - foo4 
`-- 5 - foo5 

5 directories 

#this will only print the generated mv command: 

kent$ ls -F|grep "/$"|sort|awk 'BEGIN{FS=" - ";l=5;}{o=$0;gsub("/$","",o);gsub($1"/$",l--);if(o!=$0)printf "mv \"%s\" \"%s\"\n",o,$0 }' 
mv "1 - foo1" "1 - foo5" 
mv "2 - foo2" "2 - foo4" 
mv "4 - foo4" "4 - foo2" 
mv "5 - foo5" "5 - foo1" 

# if you pipe the generated command to "sh", they will be executed: 

kent$ ls -F|grep "/$"|sort|awk 'BEGIN{FS=" - ";l=5;}{o=$0;gsub("/$","",o);gsub($1"/$",l--);if(o!=$0)printf "mv \"%s\" \"%s\"\n",o,$0 }' |sh 


#result: 

kent$ tree -d 
. 
|-- 1 - foo5 
|-- 2 - foo4 
|-- 3 - foo3 
|-- 4 - foo2 
`-- 5 - foo1 

5 directories 
+0

謝謝你的嘗試。不幸的是,它不工作,因爲我喜歡它。請注意,所有目錄名稱都以數字開頭,後跟[空格] [破折號] [空格],後跟一些文字。該文本每次都不一樣,並且不一定包含數字。 – zigamilek 2012-07-19 14:17:29

1

讓我們先來模擬一些文件名:

$ printf 'kjdfh8\nskdjfh9\nckjhv10\naskjdh11\n' 
kjdfh8 
skdjfh9 
ckjhv10 
askjdh11 

然後通過管道運行「時間:

$ printf 'kjdfh8\nskdjfh9\nckjhv10\naskjdh11\n' | sed 's/[^0-9]*\(.*\)/\1 &/' | sort -nr | cut -d\ -f2- 
askjdh11 
ckjhv10 
skdjfh9 
kjdfh8 

這是如何工作的?這其實很簡單。首先,我們使用sed將任何數字內容的副本放在行首。接下來,我們排序。最後,我們使用cut去除行首的數字。瞧!

現在...這只是顛倒了順序。這是你問題中的問題之一,但你的最終目標是重命名事情。我們可以用另一個也是while循環的管道來擴展上面的列表。這次我會把事情放在一邊以便閱讀。

#!/bin/bash 

n=0 
printf 'kjdfh8\nskdjfh9\nckjhv10\naskjdh11\n' \ 
| sed 's/[^0-9]*\(.*\)/\1 &/' | sort -nr | cut -d\ -f2- \ 
| while read file; do 
    base="${file/[0-9]*/}" 
    ((n++)) 
    printf 'mv "%s" "%s%s"\n' "$file" "$base" "$n" 
    done 

這個while循環讀入我們上面創建的文件列表。它通過從第一個數字開始刪除文件名中的所有內容來獲得「基礎」。它遞增一個計數器(用於新名稱),然後用舊文件名,基數和計數器打印mv命令。

此腳本的輸出是一組mv命令,您可以通過shell進行管道傳輸。

顯然,要在您的文件上使用此命令,您需要用生成文件列表的東西替換最初的printf命令。

注意:通常以這種方式處理文件名是不可取的,因爲意外或特殊字符(甚至是空格)在文件名中出現並拋出計劃的風險。只有在您確信自己明白了的情況下才能做到這一點。

0

此:

find /path/to/the/directories/location/ -depth -exec mv '{}' $(basename '{}')$(echo $(date "+%H%M%S%N")) \;