여러 디렉터리에 있는 한 파일에서 다른 파일로 패턴 이름을 반복적으로 바꾸는 방법

여러 디렉터리에 있는 한 파일에서 다른 파일로 패턴 이름을 반복적으로 바꾸는 방법

여러 개의 디렉토리가 있고 이를 반복적으로 반복하여 파일 이름을 변경하고 싶습니다.

*.GEOT14246.*

도착하다

*.GEOT15000.*

bash 스크립트에 이 작업을 수행하는 줄이 있습니까? 아니면 for 루프가 있는 스크립트를 작성해야 합니까? 내 시도는 (작동하지 않음) 다음과 같습니다.

#!/bin/bash

for file in `find . -type f -name "*.GEOT14246.*"`  
do
    echo "file = $file"
    mv $file *.GEOT15000.*
done

그런 다음 전화합니다.

cd /path/to/script/
sh ./script1.sh /path/to/starting/dir

분명히 이것은 시작 디렉터리 경로를 매개 변수로 전달한다고 생각하지 않기 때문에 작동하지 않는 것 같습니다. 저는 Unix를 처음 접하는데, 어떤 디렉터리에서 검색을 시작해야 하는지 알려주기 위해 매개 변수를 어떻게 전달하고 스크립트가 작동하도록 하려면 어떻게 해야 합니까?

답변1

이것은 작동합니다:

find . -type f -name "*.GEOT14246.*" -print0 | \
xargs -0 rename 's/GEOT14246/GEOT15000/'

이름이 지정된 디렉토리가 없다고 가정하면*.GEOT14246.*


find를 사용하는 bash 변형은 다음과 같습니다.

while IFS= read -r -d $'\0' file; do
    printf "MV: %-40s => %s\n" "$file" "${file/GEOT14246/GEOT15000}"
    mv "$file" "${file/GEOT14246/GEOT15000}"
done < <(find . -type f -name "*.GEOT14246.*" -print0)
              |                                 |
              +--- this is starting directory   +--- This ensures no hiccup
                                                     if newline etc. in name

상대적이지만 완전한 경로는 find에서 전달됩니다. printf이는 명령문에서 확인해야 합니다.

새 이름은 bash를 사용하여 컴파일됩니다.

${some_variable/find/replace}

find모든 용도를 바꾸십시오 :

${some_variable//find/replace}

등.여기에서 더 알아보기. 이것은 또한 좋은 읽기가 될 수 있습니다:배쉬 트랩,찾기 사용.

다음과 같은 가이드를 읽어보세요.배쉬 가이드. 온라인에서 몇 가지 튜토리얼을 찾았지만 일반적으로 신뢰하지 않습니다. 여기나 irc.freenode.net #bash에서 문의하세요.


스크립트를 호출할 필요는 없습니다 sh. 이는 Bourne Again 쉘(bash)이 아니라 Bourne 쉘(sh)이라고도 합니다. bash로 실행할 계획이라면 문제가 있습니다 bash file. .sh확장명도 부적절합니다.

일반적으로 수행하는 작업은 다음을 통해 파일을 실행 가능하게 만드는 것입니다.

chmod +x script_file

그런 다음 실행하십시오.

./script_file

이것셰르본스크립트가 실행되어야 하는 환경을 담당합니다.


스크립트에서는 전달된 경로 이름을 어디에도 사용하지 않습니다. 스크립트에는 $0스크립트 이름, $1첫 번째 매개변수, $2두 번째 매개변수 등으로 시작하는 "매개변수 목록"이 있습니다.

스크립트에서 다음과 같은 작업을 수행합니다.

# Check if argument 1 is a directory, if not exit with error
if ! [[ -d "$1" ]]; then
    printf "Usage: %s [PATH]\n" "$(basename "$0")" >&2
    exit 1
fi

# OK
path="$1"

while ...

done < <(find "$path" -type f ...)

현재 mv명령문은 명령을 실행하는 곳 어디든 모든 파일을 이동합니다..GEOT14246.(모든 mv진술을 다루는 것과 같습니다):

스크립트가 실행되기 전:

$ tree
.
└── d1
    ├── a1
    │   ├── a2
    │   │   ├── a3
    │   │   │   └── foo.GEOT14246.faa
    │   │   └── foo.GEOT14246.faa
    │   └── foo.GEOT14246.faa
    └── b1
        ├── b2
        │   ├── b3
        │   │   └── foo.GEOT14246.faa
        │   └── foo.GEOT14246.faa
        └── foo.GEOT14246.faa

스크립트가 실행된 후:

$ tree
.
├── d1
│   ├── a1
│   │   └── a2
│   │       └── a3
│   └── b1
│       └── b2
│           └── b3
└── *.GEOT15000.*

또한 공백이나 기타 이상한 내용이 포함된 파일/경로로 인해 스크립트가 손상되고 혼란을 초래할 수 있습니다. 따라서 변수를 인용해야 합니다(예 "$file": ).

답변2

Bash 4.0 이상에서는 globstar를 사용할 수도 있습니다.

shopt -s globstar
for f in **/*GEOT14246*; do mv "$f" "$f{/14246/15000}"; done
rename s/14246/15000/ **/*GEOT14246*
  • glob 패턴은 GEOT14246이 포함된 폴더와도 일치합니다.
  • 두 옵션 모두 전체 경로에 적용됩니다.
  • glob 패턴 확장 길이를 초과하는 경우getconf ARG_MAX

또는 찾기 및 읽기를 사용하십시오.

find . -name '*GEOT14246*' | while read f; do mv "$f" "${f/14246/15000}"; done
  • -print0경로에 개행 문자가 포함되어 있지 않으면 필요하지 않습니다.
  • IFS=IFS에서 경로가 문자로 시작하거나 끝나지 않는 경우에는 필요하지 않습니다.
  • -r경로에 백슬래시가 포함되어 있지 않으면 필요하지 않습니다.
  • < <()변수나 while 루프 외부의 항목을 수정하지 않으면 다음이 필요하지 않습니다.

답변3

Bash에는 간단한 단일 라이너가 없지만 zsh에는 있습니다. 그런 autoload -U zmv다음 ~/.zshrc.zmv그리고 zsh와일드카드그리고매개변수 대체.

zmv '/path/to/starting/dir/**/*GEOT14246*' '${f//GEOT14246/GEOT15000}'

이는 GEOT14246파일 이름도 대체합니다. 두 매개변수 zmv를 다시 구문 분석하려면 두 매개변수를 모두 묶어야 합니다 .

Linux에서는 bash 또는 zsh를 통해 다음을 사용할 수 있습니다.rename대신에. 이는 GEOT14246각 경로의 첫 번째 항목만 대체합니다.

rename GEOT14246 GEOT15000 /path/to/starting/dir/**/*GEOT14246*

**Bash에서는 먼저 재귀 glob을 활성화 해야 합니다 shopt -s globstar(이 줄을 yours 에 추가하세요 ~/.bashrc).

Linux 배포판이 Debian, Ubuntu 또는 그 파생 제품인 경우rename명령이 다릅니다. 다음 방법 중 하나를 사용하십시오.

rename.ul GEOT14246 GEOT15000 /path/to/starting/dir/**/*GEOT14246*
rename 's/GEOT14246/GEOT15000/g' /path/to/starting/dir/**/*GEOT14246*

관련 정보