Unix에서 패턴을 기반으로 여러 파일 이름 바꾸기


249

디렉토리에 prefix로 시작하는 여러 파일이 있습니다 ( fgh예 :

fghfilea
fghfileb
fghfilec

prefix로 시작하도록 모든 이름을 바꾸고 싶습니다 jkl. 각 파일의 이름을 개별적으로 바꾸는 대신 단일 명령을 수행해야합니까?


1
여기를 확인하십시오 : theunixshell.blogspot.com/2013/01/…
Vijay

답변:


290

몇 가지 방법이 있지만 사용 rename하는 것이 가장 쉬울 것입니다.

하나의 버전 사용 rename:

rename 's/^fgh/jkl/' fgh*

다른 버전을 사용하면 rename( Judy2K의 답변 과 동일 ) :

rename fgh jkl fgh*

플랫폼 설명서 페이지를 확인하여 위 중 어느 것이 적용되는지 확인해야합니다.


7
+1 이름 바꾸기조차 알지 못했습니다 ... 이제 mv 및 sed와 함께 for 루프 사용을 중단 할 수 있습니다 ... 감사합니다!
balpha

2
당신은 다른에 연결하고 rename다음 구문 보이고있다 unixhelp.ed.ac.uk/CGI/man-cgi?rename하는 것은 다른 일이다
Hasturkun

7
모든 * nix 시스템에 존재하지는 않습니다. 하나의 Max OS X에는없고, 그것을 구할 수있는 패키지도 없습니다. MacPorts를 보지 않았습니다.
dmckee --- 전 운영자 고양이 새끼 고양이

6
AFAICT rename는 Linux 전용 스크립트 또는 유틸리티 인 것 같습니다. 이식성에 관심이 있다면 계속 사용 sed하고 루프 또는 인라인 Perl 스크립트를 사용하십시오.
D.Shawley

33
brew install renameOS X :)
sam

117

이것은 어떻게 sed하고 mv이름 바꾸기를 할 함께 사용할 수 있습니다 :

for f in fgh*; do mv "$f" $(echo "$f" | sed 's/^fgh/jkl/g'); done

아래 주석에 따라 파일 이름에 공백이 있으면 따옴표는 파일을 이동하기 위해 이름을 반환하는 하위 함수 를 둘러싸 야 할 수 있습니다 .

for f in fgh*; do mv "$f" "$(echo $f | sed 's/^fgh/jkl/g')"; done

1
아주 근접한. fgh의 첫 번째 항목 인 's / ^ fgh / jkl / g'만 일치 시키십시오 (캐럿은 모든 차이를 만듭니다).
Stephan202

2
정확하게하기 위해서 ... "fgh의 첫 번째 발생"이 아니라 "이름의 시작 부분에 fgh"를 ​​의미합니다. / ^ fgh /는 "fghi"와 일치하지만 "efgh"와는 일치하지 않습니다.
Dave Sherohman

@ Stephan, 그건 내 부분의 오타였습니다 (고정).
nik

5
"이름 바꾸기"에 액세스 할 수없는 경우이 방법이 효과적입니다. 파일 이름에 공백이 있으면 코드에 따옴표가 필요할 수 있습니다. for f in fgh*; do mv "$f" "$(echo $f | sed 's/^fgh/jkl/g')"; done
Dave Nelson

1
@nik 따옴표없이이 파일 목록의 이름을 바꾸면 오류가 발생 touch fghfilea fghfileb fghfilec fghfile\ d합니다.. @DaveNelson의 발언을 고려하는 것이 좋습니다.
luissquall 2016 년

75

모든 시스템에 이름 바꾸기가있는 것은 아닙니다. 그래서 그것을 가지고 있지 않다면, bash shell 에서이 예제를 사용하십시오.

for f in fgh*; do mv "$f" "${f/fgh/xxx}";done

1
이 솔루션에서는 sed명령이 필요하지 않습니다. 이것은 @nik의 답변보다 간단합니다.
Halil

xxx는 교체를 의미합니까? 원래 포스터의 경우 "jkl"
Awinad

1
그들 모두의 가장 깨끗한 해결책.
MT Head

3
아마도 이것은 POSIX sh또는 일반적으로 다른 쉘 에는 존재하지 않는 Bash 확장이라고 강조합니다 .
tripleee

달콤한-유닉스 세계에는 모호한 코너가 너무 많아서 이전에는 본 적이 없습니다.
wcochran

40

mmv 사용 :

mmv "fgh*" "jkl#1"

1
와우, 이것은 문제를 해결하는 훌륭하고 간단한 방법입니다! mmv를 소개하게되어 기쁩니다. 감사합니다!
Hendeca

1
감사!!! 전에 mmv에 대해 들어 본 적이 없었습니다. 간단하고 강력하게 설치하고 가지고 놀았습니다.
Nick Rice

3
일괄 이름 바꾸기를 재귀 적으로 사용 ;하려면와 함께 사용하십시오 #1. 예 :mmv ";fgh*" "#1jkl#2"
Alp

매우 우아한 솔루션!
Fermat의 작은 학생

1
정확히 내가 필요한 것. ' '로 그룹을 캡처 하고 # 1, # 2, ...로 다시 호출합니다. EX : mmv "my show ep 1080p. *" "my.show. # 1. # 2"= my.show.001.avi
Lundy

20

여러 가지 방법이 있습니다 (이들 모두가 모든 유닉스 시스템에서 작동하는 것은 아닙니다) :

  • ls | cut -c4- | xargs -I§ mv fgh§ jkl§

    §는 편리한 것으로 대체 될 수 있습니다. 당신도 이것을 할 수는 find -exec있지만 많은 시스템에서 미묘하게 다르게 행동합니다.

  • for f in fgh*; do mv "$f" "${f/fgh/jkl}";done

    그들이 말한대로 조잡하지만 효과적

  • rename 's/^fgh/jkl/' fgh*

    정말 아름답지만 BSD에는 가장 일반적인 유닉스 시스템 인 이름 바꾸기가 없습니다.

  • rename fgh jkl fgh*

  • ls | perl -ne 'chomp; next unless -e; $o = $_; s/fgh/jkl/; next if -e; rename $o, $_';

    Perl을 사용한다고 주장하지만 시스템에 이름을 바꾸지 않은 경우이 몬스터를 사용할 수 있습니다.

그중 일부는 약간 복잡하고 목록이 완전하지는 않지만 거의 모든 유닉스 시스템에서 원하는 것을 찾을 수 있습니다.


2
나는 이런 종류의 괴물을 좋아한다!
lefakir

그래, 난 여전히 펄에 대한 약점을 가지고 있습니다 :)
iwein


파일 이름에 공백이 있으면 Perl 괴물이 완벽하게 작동합니다.
mlerley

13
rename fgh jkl fgh*

6
내 컴퓨터에서 이것은 (eval 1) 라인 1에서 "strict subs"를 사용하는 동안 'Bareword "fgh"는 허용되지 않습니다.'라는 오류가 발생합니다.
Stephan202

@ Stephan202, 당신의 기계는 무엇입니까?
nik

우분투 8.10 (펄 v5.10.0 / 2009-06-26)
Stephan202

@ Stephan202 같은 문제가 있습니다. 해결 했습니까? (7 년 후)
whossname

1
@whossname : 죄송합니다. 기억이 나지 않습니다. (휴일로 인해 답변이 느리게 진행됩니다.)
Stephan202

8

사용 find, xargssed:

find . -name "fgh*" -type f -print0 | xargs -0 -I {} sh -c 'mv "{}" "$(dirname "{}")/`echo $(basename "{}") | sed 's/^fgh/jkl/g'`"'

@nik의 솔루션 보다 복잡 하지만 파일 이름을 재귀 적으로 바꿀 수 있습니다. 예를 들어

.
├── fghdir
│   ├── fdhfilea
│   └── fghfilea
├── fghfile\ e
├── fghfilea
├── fghfileb
├── fghfilec
└── other
    ├── fghfile\ e
    ├── fghfilea
    ├── fghfileb
    └── fghfilec

이것으로 변형 될 것입니다.

.
├── fghdir
│   ├── fdhfilea
│   └── jklfilea
├── jklfile\ e
├── jklfilea
├── jklfileb
├── jklfilec
└── other
    ├── jklfile\ e
    ├── jklfilea
    ├── jklfileb
    └── jklfilec

그것을 작동시키는 열쇠 는 xargs에서 쉘xargs호출하는 것 입니다.


1
이런 식으로 글을 올렸지 만 올바른 명령을 내리려면 한 시간이
Juan Mendes

3

Perl 이름 바꾸기 스크립트 를 설치하려면 다음을 수행하십시오 .

sudo cpan install File::Rename

Stephan202의 답변에 언급 된 바와 같이 두 가지 이름 이 있습니다 . 데비안 기반 배포판의 이름Perl 입니다. Redhat / rpm 배포판의 이름C 입니다.
OS X에는 기본적으로 설치되어 있지 않으며 (10.8 이상) Windows / Cygwin도 없습니다.


3

명령 행 Groovy를 사용하여 수행하는 방법은 다음과 같습니다.

groovy -e 'new File(".").eachFileMatch(~/fgh.*/) {it.renameTo(it.name.replaceFirst("fgh", "jkl"))}'

2

Solaris에서는 다음을 시도 할 수 있습니다.

for file in `find ./ -name "*TextForRename*"`; do 
    mv -f "$file" "${file/TextForRename/NewText}"
done

루프 에서 파일 이름을 인용하면 반 포인트를 얻지 만 for file in $(find)근본적으로 결함이 있으며 인용 부호로 수정할 수 없습니다. 경우 find반환 ./file name with spaces당신이 얻을 것이다 for돌이를 ./file, name, with, 및 spaces도움 (또는 필요) 할 루프 내에서 인용 아무리.
tripleee

2
#!/bin/sh

#replace all files ended witn .f77 to .f90 in a directory

for filename in *.f77
do 
    #echo $filename
    #b= echo $filename | cut -d. -f1
    #echo $b    
    mv "${filename}" "${filename%.f77}.f90"    
done

2

이 스크립트는 아마도 공백을 포함 할 수있는 디렉토리 / 파일 이름으로 재귀 이름을 바꾸는 데 도움이되었습니다.

find . -type f -name "*\;*" | while read fname; do
    dirname=`dirname "$fname"`
    filename=`basename "$fname"`
    newname=`echo "$filename" | sed -e "s/;/ /g"`
    mv "${dirname}/$filename" "${dirname}/$newname"
done

sed이 예제에서 모든 발생을 ;space로 바꾸는 표현식에 주목하십시오 . 이것은 물론 특정 요구에 따라 교체해야합니다.


고마워요! 대본
Walter Schrabmair

1

사용 StringSolver의 어떤 프로세스의 예에 의해 도구 (윈도우 및 리눅스 bash는)

filter fghfilea ok fghreport ok notfghfile notok; mv --all --filter fghfilea jklfilea

먼저 예제를 기반으로 필터를 계산합니다 . 여기서 입력은 파일 이름 및 출력 (ok 및 notok, 임의 문자열)입니다. filter에 --auto 옵션이 있거나이 명령 이후에 단독으로 호출 된 경우 폴더 ok와 폴더를 작성하고 notok파일을 각각 해당 폴더 로 푸시합니다.

그런 다음 필터를 사용하여 mv명령은 반자동 이동 이며 수정 자 --auto를 사용하여 자동으로 변경됩니다. --filter하기 이전 필터 감사를 사용하면,에서 매핑 발견 fghfilea에를 jklfilea하고 필터링 된 모든 파일에 적용됩니다.


다른 단선 솔루션

동일한 방법을 사용하는 다른 동등한 방법 (각 줄은 동일 함)을 사용하여 좋아하는 방법을 선택할 수 있습니다.

filter fghfilea ok fghreport ok notfghfile notok; mv --filter fghfilea jklfilea; mv
filter fghfilea ok fghreport ok notfghfile notok; auto --all --filter fghfilea "mv fghfilea jklfilea"
# Even better, automatically infers the file name
filter fghfilea ok fghreport ok notfghfile notok; auto --all --filter "mv fghfilea jklfilea"

다단계 솔루션

명령이 제대로 수행되고 있는지주의 깊게 찾으려면 다음을 입력하십시오.

filter fghfilea ok
filter fghfileb ok
filter fghfileb notok

필터가 양호하다고 확신하면 첫 번째 이동을 수행하십시오.

mv fghfilea jklfilea

테스트하고 이전 필터를 사용하려면 다음을 입력하십시오.

mv --test --filter

변환이 원하는 것이 아닌 경우 (예 : mv --explain무언가 잘못되었다고 해도 ) mv --clear파일 이동을 다시 시작하도록 입력 하거나 mv input1 input2input1 및 input2가 다른 예인 경우 더 많은 예를 추가 할 수 있습니다.

자신감이 있으면 입력하십시오.

mv --filter

그리고 voilà! 모든 이름 변경은 필터를 사용하여 수행됩니다.

면책 조항 : 나는 학업 목적으로 만든이 작품의 공동 저자입니다. 배쉬 생성 기능도 곧있을 수 있습니다.


1

Ruby에서이 작업을 수행하는 것이 훨씬 쉬웠습니다. 다음은 두 가지 예입니다.

# for your fgh example. renames all files from "fgh..." to "jkl..."
files = Dir['fgh*']

files.each do |f|
  f2 = f.gsub('fgh', 'jkl')
  system("mv #{f} #{f2}")
end

# renames all files in directory from "021roman.rb" to "021_roman.rb"
files = Dir['*rb'].select {|f| f =~ /^[0-9]{3}[a-zA-Z]+/}

files.each do |f|
  f1 = f.clone
  f2 = f.insert(3, '_')
  system("mv #{f1} #{f2}")
end

1

이름 바꾸기 사용 :

$ renamer --find /^fgh/ --replace jkl * --dry-run

--dry-run출력 결과가 만족 스러우면 플래그를 제거 하십시오.


1

대량 파일 이름 바꾸기의 내 버전 :

for i in *; do
    echo "mv $i $i"
done |
sed -e "s#from_pattern#to_pattern#g” > result1.sh
sh result1.sh

스크립트를 실행하기 전에 확인하는 기능이 마음에
듭니다

공백, 따옴표 또는 다른 셸 메타 문자가 포함 된 파일 이름이 크게 손상됩니다.
tripleee

1

이 문제를 해결하는 자체 스크립트를 사용하는 것이 좋습니다. 또한 파일 이름의 인코딩을 변경하고 분음 부호를 미리 작성된 문자로 변환하는 옵션이 있습니다. Mac에서 파일을 복사 할 때 항상 발생하는 문제입니다.

#!/usr/bin/perl

# Copyright (c) 2014 André von Kugland

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

$help_msg =
"rename.pl, a script to rename files in batches, using Perl
           expressions to transform their names.
Usage:
    rename.pl [options] FILE1 [FILE2 ...]
Where options can be:
    -v                      Verbose.
    -vv                     Very verbose.
    --apply                 Really apply modifications.
    -e PERLCODE             Execute PERLCODE. (e.g. 's/a/b/g')
    --from-charset=CS       Source charset. (e.g. \"iso-8859-1\")
    --to-charset=CS         Destination charset. (e.g. \"utf-8\")
    --unicode-normalize=NF  Unicode normalization form. (e.g. \"KD\")
    --basename              Modifies only the last element of the path.
";

use Encode;
use Getopt::Long;
use Unicode::Normalize 'normalize';
use File::Basename;
use I18N::Langinfo qw(langinfo CODESET);

Getopt::Long::Configure ("bundling");

# ----------------------------------------------------------------------------------------------- #
#                                           Our variables.                                        #
# ----------------------------------------------------------------------------------------------- #

my $apply = 0;
my $verbose = 0;
my $help = 0;
my $debug = 0;
my $basename = 0;
my $unicode_normalize = "";
my @scripts;
my $from_charset = "";
my $to_charset = "";
my $codeset = "";

# ----------------------------------------------------------------------------------------------- #
#                                        Get cmdline options.                                     #
# ----------------------------------------------------------------------------------------------- #

$result = GetOptions ("apply" => \$apply,
                      "verbose|v+" => \$verbose,
                      "execute|e=s" => \@scripts,
                      "from-charset=s" => \$from_charset,
                      "to-charset=s" => \$to_charset,
                      "unicode-normalize=s" => \$unicode_normalize,
                      "basename" => \$basename,
                      "help|h|?" => \$help,
                      "debug" => \$debug);

# If not going to apply, then be verbose.
if (!$apply && $verbose == 0) {
  $verbose = 1;
}

if ((($#scripts == -1)
  && (($from_charset eq "") || ($to_charset eq ""))
  && $unicode_normalize eq "")
  || ($#ARGV == -1) || ($help)) {
  print $help_msg;
  exit(0);
}

if (($to_charset ne "" && $from_charset eq "")
  ||($from_charset eq "" && $to_charset ne "")
  ||($to_charset eq "" && $from_charset eq "" && $unicode_normalize ne "")) {
  $codeset = langinfo(CODESET);
  $to_charset = $codeset if $from_charset ne "" && $to_charset eq "";
  $from_charset = $codeset if $from_charset eq "" && $to_charset ne "";
}

# ----------------------------------------------------------------------------------------------- #
#         Composes the filter function using the @scripts array and possibly other options.       #
# ----------------------------------------------------------------------------------------------- #

$f = "sub filterfunc() {\n    my \$s = shift;\n";
$f .= "    my \$d = dirname(\$s);\n    my \$s = basename(\$s);\n" if ($basename != 0);
$f .= "    for (\$s) {\n";
$f .= "        $_;\n" foreach (@scripts);   # Get scripts from '-e' opt. #
# Handle charset translation and normalization.
if (($from_charset ne "") && ($to_charset ne "")) {
  if ($unicode_normalize eq "") {
    $f .= "        \$_ = encode(\"$to_charset\", decode(\"$from_charset\", \$_));\n";
  } else {
    $f .= "        \$_ = encode(\"$to_charset\", normalize(\"$unicode_normalize\", decode(\"$from_charset\", \$_)));\n"
  }
} elsif (($from_charset ne "") || ($to_charset ne "")) {
    die "You can't use `from-charset' nor `to-charset' alone";
} elsif ($unicode_normalize ne "") {
  $f .= "        \$_ = encode(\"$codeset\", normalize(\"$unicode_normalize\", decode(\"$codeset\", \$_)));\n"
}
$f .= "    }\n";
$f .= "    \$s = \$d . '/' . \$s;\n" if ($basename != 0);
$f .= "    return \$s;\n}\n";
print "Generated function:\n\n$f" if ($debug);

# ----------------------------------------------------------------------------------------------- #
#                 Evaluates the filter function body, so to define it in our scope.               #
# ----------------------------------------------------------------------------------------------- #

eval $f;

# ----------------------------------------------------------------------------------------------- #
#                  Main loop, which passes names through filters and renames files.               #
# ----------------------------------------------------------------------------------------------- #

foreach (@ARGV) {
  $old_name = $_;
  $new_name = filterfunc($_);

  if ($old_name ne $new_name) {
    if (!$apply or (rename $old_name, $new_name)) {
      print "`$old_name' => `$new_name'\n" if ($verbose);
    } else {
      print "Cannot rename `$old_name' to `$new_name'.\n";
    }
  } else {
    print "`$old_name' unchanged.\n" if ($verbose > 1);
  }
}

2
참고 것을 링크 전용 답변 낙심, SO 응답 솔루션 (대 아직 시간이 지남에 따라 부패하는 경향 참조의 다른 경유지)에 대한 검색의 엔드 포인트이어야한다. 링크를 참조로 유지하면서 여기에 독립형 시놉시스를 추가하십시오.
kleopatra

예측대로 @kleopatra 링크가 되었든stale over time
Y2K-하기 Shubham

1
@ y2k-shubham, 더 이상은 아닙니다.
André von Kugland

0

이것은 regexp를 사용하여 나를 위해 일했습니다.

파일 이름을 다음과 같이 바꾸고 싶었습니다.

file0001.txt -> 1.txt
ofile0002.txt -> 2.txt 
f_i_l_e0003.txt -> 3.txt

[az | _] + 0 * ([0-9] +. ) regexp를 사용하십시오. 여기서 ([0-9] +. )는 이름 바꾸기 명령에 사용할 그룹 하위 문자열 입니다.

ls -1 | awk 'match($0, /[a-z|\_]+0*([0-9]+.*)/, arr) { print   arr[0]  " "  arr[1] }'|xargs  -l mv

생산 :

mv file0001.txt 1.txt
mv ofile0002.txt 2.txt
mv f_i_l_e0003.txt 3.txt

다른 예시:

file001abc.txt -> abc1.txt
ofile0002abcd.txt -> abcd2.txt 

ls -1 | awk 'match($0, /[a-z|\_]+0*([0-9]+.*)([a-z]+)/, arr) { print   arr[0]  " "  arr[2] arr[1] }'|xargs  -l mv

생산 :

  mv file001abc.txt abc1.txt
  mv ofile0002abcd.txt abcd2.txt 

경고하십시오.


0

찾은 파일의 이름을 .avi로 재귀 적으로 바꾸는 모든 .mkv 파일을 검색하기 위해이 스크립트를 작성했습니다. 니즈에 맞게 사용자 정의 할 수 있습니다. 나중에 무언가를 참조해야 할 경우를 대비하여 파일 경로에서 파일 디렉토리, 확장자, 파일 이름 가져 오기와 같은 다른 것들을 추가했습니다.

find . -type f -name "*.mkv" | while read fp; do 
fd=$(dirname "${fp}");
fn=$(basename "${fp}");
ext="${fn##*.}";
f="${fn%.*}";
new_fp="${fd}/${f}.avi"
mv -v "$fp" "$new_fp" 
done;

0

실행하기위한 일반 스크립트 sed파일의 목록에 표현합니다 (통합 sed솔루션rename솔루션을 ) :

#!/bin/sh

e=$1
shift

for f in $*; do
    fNew=$(echo "$f" | sed "$e")
    mv "$f" "$fNew";
done

sed다음과 같이 스크립트에 표현식 을 전달한 다음 파일 목록을 전달하여 호출하십시오 rename.

script.sh 's/^fgh/jkl/' fgh*

0

아래 스크립트를 사용할 수도 있습니다. 터미널에서 실행하기가 매우 쉽습니다 ...

// 한 번에 여러 파일 이름 바꾸기

for file in  FILE_NAME*
do
    mv -i "${file}" "${file/FILE_NAME/RENAMED_FILE_NAME}"
done

예:-

for file in  hello*
do
    mv -i "${file}" "${file/hello/JAISHREE}"
done

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.