파일 이름 첫 글자를 기준으로 AZ 폴더로 파일을 구성하는 방법


15

첫 글자로 1000 개가 넘는 글꼴을 구성하는 방법 (바람직하게는 터미널)을 찾고 있습니다.

기본적으로 디렉토리를 A-Z, #만든 다음 파일 이름 첫 문자를 기준으로 글꼴 파일을 해당 디렉토리 로 이동하십시오. 숫자 [0-9]로 시작하거나 다른 특수 문자로 시작하는 글꼴은 #디렉토리 로 이동됩니다 .


해당 문자로 시작하는 파일이 없어도 디렉토리를 작성 하시겠습니까?
Arronical

@Arronical Nope. 파일이있는 것처럼.
Parto

답변:


13

늦은 파이썬 옵션 :

#!/usr/bin/env python3
import os
import sys
import shutil

def path(dr, f): return os.path.join(dr, f)

dr = sys.argv[1]
for f in os.listdir(dr):
    fsrc = path(dr, f)
    if os.path.isfile(fsrc):
        s = f[0]; target = path(dr, s.upper()) if s.isalpha() else path(dr, "#")
        if not os.path.exists(target):
            os.mkdir(target)
        shutil.move(fsrc, path(target, f))

사용하는 방법

  1. 스크립트를 빈 파일로 복사하여 다른 이름으로 저장하십시오. move_files.py
  2. 디렉토리를 인수로 사용하여 실행하십시오.

    python3 /path/to/move_files.py /path/to/files
    

스크립트는 실제로 필요한 경우 (하위) 디렉토리 (-ies) (대문자) 만 작성합니다.

설명

스크립트 :

  • 파일을 나열하고 첫 번째 문자를 가져옵니다 (소스 경로 정의).

    for f in os.listdir(dr):
        s = f[0]; fsrc = path(dr, f)
  • 항목이 파일인지 확인합니다.

    if os.path.isfile(fsrc):
  • 첫 번째 문자가 알파인지 아닌지에 대한 대상 폴더를 정의합니다.

    target = path(dr, s.upper()) if s.isalpha() else path(dr, "#")
  • 폴더가 이미 존재하는지 여부를 확인하고 그렇지 않은 경우 작성합니다.

    if not os.path.exists(target):
        os.mkdir(target)
  • 항목을 해당 폴더로 이동합니다.

    shutil.move(fsrc, path(target, f))

야곱. 대문자 첫 글자 확인이 있습니까?
Parto

@Parto 절대적으로! 어떤 방법으로 필요합니까? (3,5 시간 수업을 확인할 수 있습니다.)
Jacob Vlijm

실제로 그렇습니다. 완벽한 구현.
Parto

고려한 후, 나는 여러 가지 이유로이 답변을하기로 결정했습니다 : 1). 무슨 일이 일어나고 있는지에 대한 설명. 2). 첫 번째 시도에서 정답이 실행 됨
Parto

11

두 개의 명령과 두 개의 정규 표현식으로 코드를 읽을 수는 있지만 읽을 수 있습니다.

mkdir -p '#' {a..z}
prename -n 's|^[[:alpha:]]|\l$&/$&|; s|^[0-9]|#/$&|' [[:alnum:]]?*

이동할 파일이 너무 많고 프로세스 인수 목록에 맞지 않는 파일이 너무 많으면 (예, 제한이 있으며 몇 킬로바이트에 불과할 수 있음) 다른 명령을 사용하여 파일 목록을 생성 할 수 있습니다. prename예 :

find -mindepth 1 -maxdepth 1 -name '[[:alnum:]]?*' -printf '%f\n' |
prename -n 's|^[[:alpha:]]|\l$&/$&|; s|^[0-9]|#/$&|'

이것은 리터럴 파일 이름을 이동시키지 않으려는 추가 이점이 있습니다 [[:alnum:]]?*글로브 패턴과 일치하는 파일이없는 경우 . find쉘 글 로빙보다 더 많은 일치 기준을 허용합니다. 대안은 nullglob쉘 옵션 을 설정하고 의 표준 입력 스트림을 닫는 것입니다 prename. 1

두 경우 모두 -n스위치를 제거하여 실제로 파일을 이동하는 방법을 보여주는 것이 아니라 파일을 실제로 이동합니다.

추가: 하여 빈 디렉토리를 다시 제거 할 수 있습니다.

rmdir --ignore-fail-on-non-empty '#' {a..z}

1 shopt -s nullglob; prename ... <&-


8

zsh, 함수 및 몇 가지 zmv명령을 신경 쓰지 않으면 :

mmv() {echo mkdir -p "${2%/*}/"; echo mv -- "$1" "$2";}
autoload -U zmv
zmv -P mmv '([a-zA-Z])(*.ttf)' '${(UC)1}/$1$2'
zmv -P mmv '([!a-zA-Z])(*.ttf)' '#/$1$2'

mmv기능은 디렉토리를 만들고 파일을 이동시킵니다. zmv그런 다음 패턴 일치 및 대체를 제공합니다. 먼저 파일 이름을 알파벳으로 시작한 다음 다른 모든 항목을 이동하십시오.

$ zmv -P mmv '([a-zA-Z])(*.ttf)' '${(UC)1}/$1$2'
mkdir -p A/
mv -- abcd.ttf A/abcd.ttf
mkdir -p A/
mv -- ABCD.ttf A/ABCD.ttf
$ zmv -P mmv '([!a-zA-Z])(*.ttf)' '#/$1$2'
mkdir -p #/
mv -- 123.ttf #/123.ttf
mkdir -p #/
mv -- 七.ttf #/七.ttf

echoin mmv의 정의 없이 다시 실행 하여 실제로 이동을 수행하십시오.


8

나중에 디렉토리 이름을 대문자로 만들거나 대문자로 파일을 이동시키는 좋은 방법을 찾지 못했습니다 rename.

mkdir {a..z} \#; for i in {a..z}; do for f in "$i"*; do if [[ -f "$f" ]]; then echo mv -v -- "$f" "$i"; fi; done; done; for g in [![:alpha:]]*; do if [[ -f "$g" ]]; then echo mv -v -- "$g" \#; fi; done

더 읽기 쉽게 :

mkdir {a..z} \#; 
for i in {a..z}; do 
  for f in "$i"*; do
    if [[ -f "$f" ]]; then 
      echo mv -v -- "$f" "$i"; 
    fi 
  done
done
for g in [![:alpha:]]*; do 
  if [[ -f "$g" ]]; then 
    echo mv -v -- "$g" \#
  fi
done

echo실제로 파일을 이동시키는 테스트 후 제거

그리고

rename -n 'y/[a-z]/[A-Z]/' *

-n테스트 후보기에 좋으면 제거 하고 다시 실행하십시오.


2
if [[ -d "${i^}" ]]가변 i자본을 mkdir {A..Z}시작 하는 데 사용할 수 있습니다 .
Arronical

이것을 시도하고 보자
Parto

@Arronical 감사합니다! 당신이 그것을 자신의 길을 게시했기 때문에 그러나 나는 그것을 떠날 것이다
Zanna

@ 잔나 나는 우리가 다른 방향에서 왔기 때문에 편지를 반복하고 검색 기준으로 사용하지 않았 음을 좋아합니다. 나는 찾기가있는 영리하고 빠른 해결책이 있다고 확신하지만 그 주위에 내 머리를 넣을 수는 없습니다!
Arronical

Zanna, 대문자로 시작하는 글꼴은 움직이지 않았습니다. 그렇지 않으면 잘 작동했습니다.
Parto

7

글꼴을 포함하는 디렉토리 내의 다음 명령이 작동해야합니다. 글꼴 저장 디렉토리 외부에서 사용하려면 for f in ./*로 변경 하십시오 for f in /directory/containing/fonts/*. 이것은 매우 쉘 기반의 방법이므로 상당히 느리며 비재 귀적입니다. 일치하는 문자로 시작하는 파일이있는 경우에만 디렉토리가 작성됩니다.

target=/directory/to/store/alphabet/dirs
mkdir "$target"
for f in ./* ; do 
  if [[ -f "$f" ]]; then 
    i=${f##*/}
    i=${i:0:1}
    dir=${i^}
    if [[ $dir != [A-Z] ]]; then 
      mkdir -p "${target}/#" && mv "$f" "${target}/#"
    else
      mkdir -p "${target}/$dir" && mv "$f" "${target}/$dir"
    fi
  fi
done

폰트 저장 디렉토리 내에서 다시 하나의 라이너로 :

target=/directory/to/store/alphabet/dirs; mkdir "$target" && for f in ./* ; do if [[ -f "$f" ]]; then i=${f##*/}; i=${i:0:1} ; dir=${i^} ; if [[ $dir != [A-Z] ]]; then mkdir -p "${target}/#" && mv "$f" "${target}/#"; else mkdir -p "${target}/$dir" && mv "$f" "${target}/$dir" ; fi ; fi ; done

bash 매개 변수 확장을 사용하여 유사한 문자열 조작으로 find를 사용하는 방법은 재귀 적이며 순수 쉘 버전보다 약간 빠릅니다.

find . -type f -exec bash -c 'target=/directory/to/store/alphabet/dirs ; mkdir -p "$target"; f="{}" ; i="${f##*/}"; i="${i:0:1}"; i=${i^}; if [[ $i = [[:alpha:]] ]]; then mkdir -p "${target}/$i" && mv "$f" "${target}/$i"; else mkdir -p "${target}/#" && mv "$f" "${target}/#"; fi' \;

또는 더 읽기 쉽게 :

find . -type f -exec bash -c 'target=/directory/to/store/alphabet/dirs 
   mkdir -p "$target"
   f="{}"
   i="${f##*/}"
   i="${i:0:1}"
   i=${i^}
   if [[ $i = [[:alpha:]] ]]; then 
      mkdir -p "${target}/$i" && mv "$f" "${target}/$i"
   else
      mkdir -p "${target}/#" && mv "$f" "${target}/#"
   fi' \;

이것도 효과가있었습니다. 대문자와 소문자의 경우에도 마찬가지입니다.
Parto

5

tr, mkdir및을 사용하여 각 파일 이름을 디렉토리 이름에 매핑하십시오 mv.

find /src/dir -type f -print0 |
xargs -0 -I{} bash -c \
  'dir=/dest/$(basename "{}" | cut -c1 | tr -C "a-zA-Z\n" "#" | tr "a-z "A-Z"); mkdir -p $dir; mv "{}" $dir'

나는 이것을 정말로 좋아합니다. 이것은 find를 사용하고 싶은 소망으로 잡고있는 것입니다. 대문자 디렉토리 이름 만 작성하고 소문자 파일 이름을 그 이름으로 옮기는 방법이 있습니까?
Arronical

1
tr대문자로 변환하기 위해 다른 것을 추가했습니다 .
xn.

우회를 통해 다시 xargs전화 하는 이유는 무엇 bash입니까? findwhile 루프에 출력을 파이프하고 read레코드별로 기록 하는 것이 더 간단하고 읽기 쉬울까요?
David Foerster

좋은 질문입니다, @DavidFoerster. 하나의 라이너에서 루프에 대한 편향과보다 기능적인 접근 방식을 선호한다고 생각합니다. 그러나 문자열의 bash 스크립트는 매우 우아하지 않으므로 while루프 버전 ( bit.ly/2j2mhyb )이 더 좋습니다.
xn.

그건 그렇고, 인수를 추가 한 다음 쉘 스크립트 내부 를 참조 {}하면 불쾌한 대체를 피할 수 있습니다 ( 예 :) . (마지막 마음 !)xargs$1xargs -0 -n1 -- bash -c 'dir=/dest/$(basename "$1" | ...); ...; mv "$1" "$dir"' __
David Foerster
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.