디렉터리를 평면화하되 새 파일 이름에 디렉터리 이름을 유지합니다.

디렉터리를 평면화하되 새 파일 이름에 디렉터리 이름을 유지합니다.

디렉터리를 다음 형식으로 어떻게 평면화할 수 있나요?

앞으로:./aaa/bbb/ccc.png

뒤쪽에:./aaa-bbb-ccc.png

답변1

여기에는 이미 좋은 답변이 있지만 다음에서 더 직관적이라고 생각합니다 bash.

find aaa -type f -exec sh -c 'new=$(echo "{}" | tr "/" "-" | tr " " "_"); mv "{}" "$new"' \;

aaa기존 디렉토리는 어디에 있습니까? 여기에 포함된 파일은 현재 디렉터리로 이동됩니다(aaa에는 빈 디렉터리만 남음). 이 두 호출은 tr디렉터리와 공백을 처리합니다(슬래시를 이스케이프 처리하는 논리 없음 - 독자를 위한 연습).

나는 이것이 더 직관적이고 상대적으로 조정하기 쉽다고 생각합니다. find즉, .png 파일만 찾으려면 매개변수를 변경할 수 있습니다. tr통화를 변경하거나 필요한 경우 더 추가할 수 있습니다 . 제대로 작동하는지 시각적으로 확인하려면 echo먼저 추가하고 추가 단계 없이 문제가 제대로 보이는 경우에만 반복하면 됩니다.mvecho

find aaa -name \*.png -exec sh -c 'new=$(echo "{}" | tr "/" "-" | tr " " "_"); echo mv "{}" "$new"' \;

또한 ... 또는 ... find aaa대신에 ... 를 사용했다는 점에 유의하십시오. 후자의 두 개는 최종 파일 이름에 흥미로운 흔적을 남길 것이기 때문입니다.find .find aaa/

답변2

경고: 대부분의 명령을 브라우저에 직접 입력했습니다. 강사에게 경고하십시오.

zsh를 사용하고즈마브:

zmv -o -i -Qn '(**/)(*)(D)' '${1//\//-}$2'

설명: 이 패턴은 **/*현재 디렉터리의 하위 디렉터리에 있는 모든 파일을 반복적으로 일치합니다(현재 디렉터리의 파일과 일치하지 않지만 이러한 파일의 이름을 바꿀 필요는 없습니다). 대괄호의 처음 두 쌍은 대체 텍스트에서 합계로 참조될 수 있는 $1그룹 입니다. $2마지막 대괄호 쌍을 추가하십시오.D 글로벌 예선이렇게 하면 파일이 누락되지 않습니다. 기존 파일을 덮어쓸지 여부를 묻는 메시지를 표시하기 위해 -o -i-i옵션을 전달하는 것을 의미합니다.mv


POSIX 도구만 사용하십시오.

find . -depth -exec sh -c '
    for source; do
      case $source in ./*/*)
        target="$(printf %sz "${source#./}" | tr / -)";
        mv -i -- "$source" "${target%z}";;
      esac
    done
' _ {} +

설명: 이 case명령문은 현재 디렉토리와 현재 디렉토리의 최상위 레벨 하위 디렉토리를 생략합니다. 선행이 제거되고 모든 슬래시가 대시로 대체된 target소스 파일 이름( )이 포함됩니다 . 마지막은 파일 이름이 개행으로 끝나는 것을 방지하는 것입니다. 그렇지 않으면 명령 대체가 이를 제거합니다.$0./zz

find당신이 그것을 지원하지 않는 경우 -exec … +(OpenBSD, 나는 당신을 찾고 있습니다):

find . -depth -exec sh -c '
    case $0 in ./*/*)
      target="$(printf %sz "${0#./}" | tr / -)";
      mv -i -- "$0" "${target%z}";;
    esac
' {} \;

bash(또는 ksh93)를 사용하면 슬래시를 대시로 바꾸기 위해 외부 명령을 호출할 필요가 없습니다. 문자열 대체 구성과 함께 ksh93 매개변수 확장을 사용할 수 있습니다 ${VAR//STRING/REPLACEMENT}.

find . -depth -exec bash -c '
    for source; do
      case $source in ./*/*)
        source=${source#./}
        target="${source//\//-}";
        mv -i -- "$source" "$target";;
      esac
    done
' _ {} +

답변3

find . -mindepth 2 -type f -name '*' |
  perl -l000ne 'print $_;  s/\//-/g; s/^\.-/.\// and print' |
    xargs -0n2 mv 

참고: 이것은 include 에서는 작동하지 않습니다 \n.
물론 이것은 유형 f파일만 이동합니다.
유일한 이름 충돌은 기존에서 발생합니다.비밀번호

테스트를 위해 이 기본 하위 집합을 사용하세요.

rm -fr junk
rm -f  junk*hello*

mkdir -p  junk/junkier/junkiest
touch    'hello    hello'
touch    'junk/hello    hello'
touch    'junk/junkier/hello    hello'
touch    'junk/junkier/junkiest/hello    hello'

~로 이어지다

./hello    hello
./junk-hello    hello
./junk-junkier-hello    hello
./junk-junkier-junkiest-hello    hello

답변4

파일 이름 + 경로를 tr명령에 파이프하면 됩니다.tr <replace> <with>

for FILE in `find aaa -name "*.png"`
do
  NEWFILE=`echo $FILE | tr '/' '-'`
  cp -v $FILE $NEWFILE
done

관련 정보