여러 개의 디렉토리가 있고 이를 반복적으로 반복하여 파일 이름을 변경하고 싶습니다.
*.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*