Jak zmienić nazwę za pomocą prefiksu / sufiksu?

95

Jak zrobić mv original.filename new.original.filenamebez ponownego wpisywania oryginalnej nazwy pliku?

Wyobrażałbym sobie, że jestem w stanie zrobić coś takiego, mv -p=new. original.filenamemoże mv original.filename new.~lub cokolwiek innego - ale nie widzę czegoś takiego po obejrzeniu man mv/ info mvpages.

Oczywiście mógłbym napisać skrypt powłoki, aby to zrobić, ale czy nie ma do tego istniejącego polecenia / flagi?

Peter Boughton
źródło

Odpowiedzi:

122

W Bash i zsh możesz to zrobić za pomocą rozszerzenia Brace . To po prostu rozszerza listę elementów w nawiasach. Na przykład:

# echo {vanilla,chocolate,strawberry}-ice-cream
vanilla-ice-cream chocolate-ice-cream strawberry-ice-cream

Możesz więc zmienić nazwę w następujący sposób:

mv {,new.}original.filename

ponieważ rozszerza się to do:

mv original.filename new.original.filename
Dave Webb
źródło
Dzięki, to wygląda na najlepsze rozwiązanie - działa również z ksh.
Peter Boughton,
29
To nie działa z dzikimi kartami. Oznacza to, że w katalogu zawierającym nazwy plików a, b, c użycie „echo {, new.} *” Daje listę „abc new. *” (Ponieważ generowanie nazwy pliku przez rozwinięcie nawiasów klamrowych następuje przed rozwinięciem symboli wieloznacznych - przynajmniej przez wnioskowanie).
Jonathan Leffler,
Od miesięcy szukam takiego rozwiązania wykorzystując tylko podstawowe funkcje powłoki ... Nigdy bym nie wymyślił czegoś tak prostego, wielkie dzięki!
flonk
Dzięki za odniesienie do rozszerzenia nawiasów klamrowych :-) dokładnie to, czego szukałem!
Pim Hazebroek
1
Uwielbiam ten przykład. Czuję się teraz w nastroju, żeby pójść do Baskin Robbins podczas przerwy na lunch.
Sridhar Sarnobat
157

Możesz użyć rename(1)polecenia:

rename 's/(.*)$/new.$1/' original.filename

Edycja: jeśli renamenie jest dostępny i musisz zmienić nazwę więcej niż jednego pliku, skrypty powłoki mogą być naprawdę krótkie i proste. Na przykład, aby zmienić nazwę wszystkich *.jpgna prefix_*.jpgw bieżącym katalogu:

for filename in *.jpg; do mv "$filename" "prefix_$filename"; done;
Simon Lehmann
źródło
Zainstalowali grafit w ten weekend i mają krok, który zasadniczo („skopiuj wszystkie pliki * .example do folderu conf, usuwając przyrostek przykładu”). Naprawdę leniwy z ich strony, ale rename 's/(.*).example/$1/' *.exampleuratował mnie od nudy.
Conrad Dean
2
Jak dotąd to najlepsza odpowiedź.
lifeisfoo
Myślę, że nie potrzebujesz pierwszego $w tym scenariuszu. Więc po prostu's/(.*)/new.$1/'
wisbucky
1
renamepolecenie nie działa na moim komputerze RHEL 6. Czy istnieją różne wersje tego polecenia? for ... donePracował dla mnie.
robsch
25

Możesz uzyskać zgodną z UNIX możliwość zmiany nazwy wielu plików (używając symboli wieloznacznych), tworząc pętlę for:

for file in *; do
  mv $file new.${file%%}
done
Muguro
źródło
7
Jaka jest różnica między tym a tym, na co odpowiedział już Simon Lehmann ?
Peter Boughton
4
To działa świetnie. Co ${file%%}robisz? Wydaje się podobne do po prostu $ {file}
Sidmitra
Ciekawi mnie też $ {file %%}
Lucas Bustamante,
10

Widziałem, jak ludzie wspominali o renamepoleceniu, ale nie jest ono rutynowo dostępne w systemach Unix (w przeciwieństwie do, powiedzmy, Linuksa lub Cygwin - w obu przypadkach zmiana nazwy jest raczej plikiem wykonywalnym niż skryptem). Ta wersja renamema dość ograniczoną funkcjonalność:

rename from to file ...

To zastępuje od części nazwy pliku z Do i przykład podany w manualu jest:

rename foo foo0 foo? foo??

To zmienia nazwę foo1 na foo01 i foo10 na foo010 itd.

Używam skryptu Perla rename, który pierwotnie wykopałem z pierwszego wydania książki Camel, około 1992, a następnie rozszerzyłem, aby zmienić nazwy plików.

#!/bin/perl -w
#
# @(#)$Id: rename.pl,v 1.7 2008/02/16 07:53:08 jleffler Exp $
#
# Rename files using a Perl substitute or transliterate command

use strict;
use Getopt::Std;

my(%opts);
my($usage) = "Usage: $0 [-fnxV] perlexpr [filenames]\n";
my($force) = 0;
my($noexc) = 0;
my($trace) = 0;

die $usage unless getopts('fnxV', \%opts);

if ($opts{V})
{
    printf "%s\n", q'RENAME Version $Revision: 1.7 $ ($Date: 2008/02/16 07:53:08 $)';
    exit 0;
}
$force = 1 if ($opts{f});
$noexc = 1 if ($opts{n});
$trace = 1 if ($opts{x});

my($op) = shift;
die $usage unless defined $op;

if (!@ARGV) {
    @ARGV = <STDIN>;
    chop(@ARGV);
}

for (@ARGV)
{
    if (-e $_ || -l $_)
    {
        my($was) = $_;
        eval $op;
        die $@ if $@;
        next if ($was eq $_);
        if ($force == 0 && -f $_)
        {
            print STDERR "rename failed: $was - $_ exists\n";
        }
        else
        {
            print "+ $was --> $_\n" if $trace;
            print STDERR "rename failed: $was - $!\n"
                unless ($noexc || rename($was, $_));
        }
    }
    else
    {
        print STDERR "$_ - $!\n";
    }
}

Pozwala to na napisanie dowolnego polecenia podstawienia Perla lub transliteracji w celu odwzorowania nazw plików. W konkretnym żądanym przykładzie użyłbyś:

rename 's/^/new./' original.filename
Jonathan Leffler
źródło
Dzięki, gdybym mógł przyjąć drugą odpowiedź, to byłoby to. Chciałem standardowego polecenia jako czegoś, co będzie działało na wszystkim, czego mógłbym użyć, ale mogę umieścić ten skrypt na maszynach, których często używam i nadal będzie pomocny.
Peter Boughton,
James Wong zauważa, że dla Arch Linux, można po prostu pobrać i zainstalować ten skrypt za pośrednictwem pacmanprzy użyciu: pacman -Sy perl-rename. Następnie dodaj do niego alias w swoim bashrc:alias rename='perl-rename'
Jonathan Leffler
co jeśli „od” lub „do” są pustymi ciągami, tj. chcesz dodać coś do każdej nazwy pliku lub całkowicie usunąć coś
Troyseph
1
@Troyseph - aby dołączyć '.htmldo nazw plików, użyj 's/$/.html/'-, aby usunąć tmpz każdego miejsca w nazwach plików, użyj 's/tmp//g'(znajdź tmpi zamień na nic wszędzie).
Jonathan Leffler
4

Najłatwiejszym sposobem zbiorczej zmiany nazw plików w katalogu jest:

ls | xargs -I fileName mv fileName fileName.suffix
Brajan Elektro
źródło
2

Jeśli jest otwarty na modyfikację, możesz użyć sufiksu zamiast przedrostka. Następnie możesz użyć uzupełniania tabulatorami, aby uzyskać oryginalną nazwę pliku i dodać sufiks.

W przeciwnym razie nie, to nie jest coś, co jest obsługiwane przez polecenie mv. Jednak prosty skrypt powłoki mógłby sobie poradzić.

workmad3
źródło
Często potrzebuję obu, ale przede wszystkim prefiksu - jak mówisz, uzupełnianie tabulatorów może obsługiwać sufiksy.
Peter Boughton,
1

W moim przypadku mam grupę plików, które wymagają zmiany nazwy, zanim będę mógł z nimi pracować. Każdy plik ma swoją rolę w grupie i ma własny wzorzec.

W rezultacie mam listę poleceń zmiany nazwy, taką jak ta:

f=`ls *canctn[0-9]*`   ;  mv $f  CNLC.$f
f=`ls *acustb[0-9]*`   ;  mv $f  CATB.$f
f=`ls *accusgtb[0-9]*` ;  mv $f  CATB.$f
f=`ls *acus[0-9]*`     ;  mv $f  CAUS.$f

Spróbuj tego również:

f=MyFileName; mv $f {pref1,pref2}$f{suf1,suf2}

Spowoduje to utworzenie wszystkich kombinacji z przedrostkami i przyrostkami:

pref1.MyFileName.suf1
...
pref2.MyFileName.suf2

Innym sposobem rozwiązania tego samego problemu jest utworzenie tablicy mapowania i dodanie odpowiedniego prefiksu dla każdego typu pliku, jak pokazano poniżej:

#!/bin/bash
unset masks
typeset -A masks
masks[ip[0-9]]=ip
masks[iaf_usg[0-9]]=ip_usg
masks[ipusg[0-9]]=ip_usg
...
for fileMask in ${!masks[*]}; 
do  
registryEntry="${masks[$fileMask]}";
fileName=*${fileMask}*
[ -e ${fileName} ] &&  mv ${fileName} ${registryEntry}.${fileName}  
done
aprodan
źródło
1

Zbiorcza zmiana nazwy plików skryptu bash

#!/bin/bash
# USAGE: cd FILESDIRECTORY; RENAMERFILEPATH/MultipleFileRenamer.sh FILENAMEPREFIX INITNUMBER
# USAGE EXAMPLE: cd PHOTOS; /home/Desktop/MultipleFileRenamer.sh 2016_
# VERSION: 2016.03.05.
# COPYRIGHT: Harkály Gergő | mangoRDI (https://wwww.mangordi.com/) 

# check isset INITNUMBER argument, if not, set 1 | INITNUMBER is the first number after renaming
if [ -z "$2" ]
    then i=1;
else
    i=$2;
fi

# counts the files to set leading zeros before number | max 1000 files
count=$(ls -l * | wc -l)
if [ $count -lt 10 ]
    then zeros=1;
else
    if [ $count -lt 100 ]
        then zeros=2;
    else
        zeros=3
    fi
fi

# rename script
for file in *
do
    mv $file $1_$(printf %0"$zeros"d.%s ${i%.*} ${file##*.})
    let i="$i+1"
done
Harkály Gergő
źródło
1

Wiem, że są tutaj świetne odpowiedzi, ale nie znalazłem odniesienia do obsługi rozszerzeń nazw plików podczas dodawania sufiksu.

Musiałem dodać sufiks „_en” do wszystkich wavplików w folderze przed rozszerzeniem pliku.

Magia jest tutaj: %.*

for filename in *.wav; do mv $filename ${filename%.*}_en.wav; done;

Jeśli potrzebujesz obsługiwać różne rozszerzenia plików, zaznacz odpowiedź. Nieco mniej intuicyjny.

yeya
źródło