나는 이 주제가 이전에 (여기 및 다른 곳에서) 논의되었다는 것을 알고 있지만 bash 스크립팅 기술을 통해 길을 찾으려고 노력하고 있으므로 양해해 주시기 바랍니다.
다음 문제를 해결해야 합니다.
내가 가지고 있는 것을 고려하면:
디렉토리 1
- 파일 1
- 파일 2
- 등...
디렉토리 2
- 파일 1
- 파일 2
- 등...
파일 이름을 바꾸고 싶습니다.
디렉토리 1
- 디렉토리1_파일1
- 디렉토리1_파일2
- dir1_잠깐...
디렉토리 2
- 디렉터리 2_파일 1
- 디렉터리 2_파일 2
- dir2_잠깐...
지금까지 나는 다음과 같은 "탐색적" bash 스크립트를 작성했습니다.
for d in `ls -d */`
do
#echo "$d"
pre="${d:0:-1}"
#echo "$pre"
#cd "${d}"
pushd "${d}"
for f in *.jp2
do
#echo "${f}"
echo "${pre}_${f}"
done
#cd -
#popd
done
오류 메시지와는 별도로 (상당히) 잘 작동하는 것 같습니다.
line 9: pushd: dir2/: No such file or directory
여기서 dir2는 for 루프가 검색한 마지막 디렉터리의 이름입니다.
도움이 필요하세요? 내가 무엇을 놓치고 있나요?
답변1
cd
디렉토리로 앞뒤로 이동 하는 대신 ( popd
대부분 pushd
대화식 사용을 위해 만들어졌습니다):
#!/bin/sh
for name in */*; do
[ ! -f "$name" ] && continue
dir="$( basename "$( dirname "$name" )" )"
newname="$dir/${dir}_${name##*/}"
if [ ! -e "$newname" ]; then
echo mv "$name" "$newname"
fi
done
이는 현재 디렉터리 내의 모든 디렉터리에 있는 모든 이름을 반복합니다. 파일이 아닌 항목은 건너뛰고 디렉터리 기본 이름(경로가 없는 디렉터리 이름)을 로 추출합니다 . 그런 다음 dir
경로 이름의 기본 이름 부분( 로 대체 가능)을 사용하여 $newname
파일에 대한 새 파일 이름을 구성합니다 .$dir
$name
${name##*/}
$( basename "$name" )
새 이름이 아직 사용되지 않은 경우 파일 이름이 변경됩니다.
echo
올바른 작업을 수행해야 한다는 것을 확인한 후에는 삭제하여 실제로 파일 이름을 바꾸세요.
다른 디렉터리에서 일련의 작업을 수행한 후 돌아오려면 다음을 사용하세요.
( cd dir
action
action
action )
디렉토리를 변경해도 아무런 효과가 없습니다 ( ... )
.
또한보십시오:왜 `ls`를 구문 분석하지 *않나요*?
답변2
"dir2는 for 루프가 검색한 마지막 디렉터리의 이름입니다"라고 말했지만 실제로는두번째드디어 그렇지 않나요? 주석을 달았기 때문에 실패합니다 popd
. 첫 번째 루프 반복이 끝나면 여전히 "in" 상태 dir1
이므로 시도는 pushd dir2
실제로 dir1/dir2
; 즉, dir2
inside 를 찾고 있습니다 dir1
.
7개의 디렉터리가 있는 경우 마지막 6개 디렉터리는 실패합니다.
"popd의 주석 처리를 제거하면 다른 원치 않는 결과가 발생할 수 있습니다. 즉, for 루프가 반복하는 디렉토리(동일 레벨)에 파일(디렉토리 아님)이 있는 경우 어떻게 될까요?"라는 우려가 제기되었습니다. 훌륭한,
- 이 논리는 "왼쪽 신발 외에 오른쪽 신발도 신으면 총의 표적이 더 많아져서 오른발로 총을 쏠 확률이 높아진다"고 말하는 것과 같습니다. .
pushd
따르지 않고 신는 것popd
(특히 사이클)은 신발 하나만 신는 것보다 훨씬 더 잘못된 것입니다. - 을 사용하고 있으므로
*/
디렉토리만 가져옵니다.for d in */
하지만 Kusalananda가 옳 습니다.for d in `ls -d */`
.
더 좋은 점은 다음과 같은 일을 할 수 있다는 것입니다.
for d in * do … if [ -d "$d" ] then pushd "$d" for f in *.jp2 do … done popd fi done
또는
for d in * do … if pushd "$d" 2> /dev/null then for f in *.jp2 do … done popd fi done
따라서 디렉토리가 아닌 것을 디렉토리로 취급하려고 시도하지 마십시오.