for 루프는 파일 이름 앞에 디렉터리 이름을 추가합니다.

for 루프는 파일 이름 앞에 디렉터리 이름을 추가합니다.

나는 이 주제가 이전에 (여기 및 다른 곳에서) 논의되었다는 것을 알고 있지만 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; 즉, dir2inside 를 찾고 있습니다 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
    

    따라서 디렉토리가 아닌 것을 디렉토리로 취급하려고 시도하지 마십시오.

관련 정보