пакетное переименование имени файла в каталоге - PullRequest
3 голосов
/ 30 ноября 2011

У меня есть несколько файлов с такими именами:

01_dpm_gsi_182.sl5
02_dpm_devel_gsi_182.sl5
03_DPM_DSI_181.sl5
04_globus_httpd_122.sl5
05_globus_httpd_client_cgi_132.sl5

Как я могу переименовать эти файлы, чтобы получить что-то вроде:

01_dpmgsi_s2011e01.sl5
02_dpmdevelgsi_s2011e02.sl5
....
....

Ближе всего мне предложили вот так:

#!/usr/bin/perl -n

if (/^([^_]+)_(.+)_([^.]+)([.].+)$/) {
    my $s = $&;
    my $x = $1;
    my $y = $2;
    my $z = 2011;
    my $e = $4;

    $y =~ s/_//g;

    print "mv $s ${x}_${y}_s${z}e$x$e\n"
}

, а затем используйте его так:

# ls | perl -n reName.pl > output
# bash ./output

Есть ли лучший способ или однострочник, чтобы сделать это, возможно, используя sed / awk? Ура !!

Ответы [ 6 ]

6 голосов
/ 30 ноября 2011

Нет необходимости использовать bash-скрипт для mv файлов, Perl может это сделать.Этот скрипт ниже использует File :: Copy для этой цели.Я закомментировал строки, которые выполняют перемещение, чтобы можно было сначала проверить сценарий с помощью ввода.

Код:

use strict;
use warnings;
use v5.10;

#use File::Copy;
my $year = 2011;
for (@ARGV) {
    my ($pre, @p) = split /_/;
    my $ext = pop @p;
    $ext =~ s/.*\./s${year}e$pre./;
    my $new = join '_', $pre, (join '', @p), $ext;
    say "old: $_";
    say "new: $new";
    say "------";
    #move $_, $new or die $!;
}

Использование:

perl script.pl *.sl5

Если у вас нет версии 5.10, замените say на print и добавьте новую строку.

Вывод:

old: 01_dpm_gsi_182.sl5
new: 01_dpmgsi_s2011e01.sl5
------
old: 02_dpm_devel_gsi_182.sl5
new: 02_dpmdevelgsi_s2011e02.sl5
------
old: 03_DPM_DSI_181.sl5
new: 03_DPMDSI_s2011e03.sl5
------
old: 04_globus_httpd_122.sl5
new: 04_globushttpd_s2011e04.sl5
------
old: 05_globus_httpd_client_cgi_132.sl5
new: 05_globushttpdclientcgi_s2011e05.sl5
2 голосов
/ 30 ноября 2011

omg, НИКОГДА не анализировать выходные данные ls или строить запросы, которые будут повторно оценены оболочкой. Анализ списка файлов (как вывод ls) невозможно получить прямо перед пробелом (или что-то еще в вашей переменной $ IFS) и, таким образом, является неловким решением в ЛЮБОЕ ВРЕМЯ. Аналогично, создание правильно экранированных командных строк оболочки практически невозможно.

Чтобы остаться с оболочкой (которая, тем не менее, является отличным инструментом для выполнения этой задачи), используйте глобализацию файлов, которая корректно разделяет аргументы:

for i in ./*
do
    firstpart=${i%%_*}
    num=${firstpart#./}
    middlepart=${i#*_}
    middlepart=${middlepart%_*}
    middlepart=`printf %s "$middlepart" | tr -d _`
    lastpart=s2011e"$num".sl5
    echo mv "$i" "${firstpart}_${middlepart}_${lastpart}"
done

Чтобы действительно выполнить, удалите echo в последней строке.

2 голосов
/ 30 ноября 2011

Это решение GNU sed может работать для вас:

 sed 'h;s/[^_.]*\././;s/_//2g;s/^\(\([^_]*\)_[^.]*\)\./\1_s2011e\2e./;x;G;s/\(.*\)\n/mv -v \1 /' file

Объяснение:

Сохраните оригинальное имя файла в поле удержания (HS).Удалите числа, предшествующие расширению файла.Удалить все, кроме первого _.Создайте новое имя файла, используя группировку, обратные ссылки и добавленный текст.Своп к ГС.Добавьте новое имя файла.Добавьте команду mv -v и удалите встроенные \n.

Как уже было сказано, имена файлов могут сбить вас с толку - будьте осторожны!

1 голос
/ 30 ноября 2011

Подобные вещи были рассмотрены ранее , и ответ заключается в использовании существующего переименования, а не в написании собственного.

1 голос
/ 30 ноября 2011

Вам не нужен отдельный скрипт bash для переименования.Perl имеет встроенную функцию rename.См. http://perldoc.perl.org/functions/rename.html для документации.

Я не буду комментировать регулярное выражение.Возможно, его можно улучшить, но пока он работает правильно, я не вижу необходимости его менять.

0 голосов
/ 30 ноября 2011

хорошо, вы запрашиваете однострочник:

ls |xargs -n1|awk -F'[_.]' '{idx=$1;nf=$1"_";for(i=2;i<NF-1;i++)nf=nf$i; nf=nf"_s2011e"idx"."$NF;print "mv "$0" "nf;}'

это напечатает все команды mv.

вы можете проверить вывод, если целевые именавсе верно.если да, просто добавьте "|sh" в конце строки, он будет переименовываться.

test (без | sh, чтобы увидеть вывод)

kent$  ls |xargs -n1|awk -F'[_.]' '{idx=$1;nf=$1"_";for(i=2;i<NF-1;i++)nf=nf$i; nf=nf"_s2011e"idx"."$NF;print "mv "$0" "nf;}'
mv 01_dpm_gsi_182.sl5 01_dpmgsi_s2011e01.sl5
mv 02_dpm_devel_gsi_182.sl5 02_dpmdevelgsi_s2011e02.sl5
mv 03_DPM_DSI_181.sl5 03_DPMDSI_s2011e03.sl5
mv 04_globus_httpd_122.sl5 04_globushttpd_s2011e04.sl5
mv 05_globus_httpd_client_cgi_132.sl5 05_globushttpdclientcgi_s2011e05.sl5
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...