파일 이름 그룹 찾기/감지

파일 이름 그룹 찾기/감지

fs에는 다음과 같은 파일이 있습니다. PREFIX_GROUPNAME_OTHERNAMES[.txt|.*]

예를 들어:

A_ABC_A.txt
A_ABC_B.txt
A_ABC_C.txt
A_XYZ_A.txt
A_XYZ_B.txt
A_XYZ_C.txt

몇 가지 추가 작업을 위해 그룹 이름을 얻고 싶습니다.

$# command i'm looking for
result:
> ABC XYZ

이름 구조는 알지만 그룹 이름은 모릅니다.

아이디어(그러나 매우 비싸 보입니다!(큰 목록에서)):

  • 모든 파일 검사
  • 이름 분할, 그룹 이름별로 목록 생성
  • 그룹으로 돌아가기

find 및 awk 아마도 tr이 솔루션을 찾을 때 찾고 있는 것 같습니다.

편집하다:

이는 고유하지 않은 목록을 제공합니다.

find ./ -iname '*.txt' | xargs -n 1 | cut -d '_' -f 2
> ABC
> ABC
> ABC
> XYZ
> XYZ
> XYZ

답변1

다음은 쉘 문자열 조작과 표준 도구만 사용하여 sort방지합니다.출력 구문 분석ls또는find, 다음과 같은 작업을 수행하지 않는 것이 좋습니다.

for f in *.*; do gr=${f#*_};gr=${gr%_*}; printf "%s\n" "$gr"; done | sort -u

귀하의 경우에는 정확하게 출력되어야 합니다.

ABC
XYZ

설명하다:

  • 일치하는 모든 파일 이름을 반복합니다 *.*(말한 대로 모든 파일 이름을 캡처하려면 "최소 포괄적" 패턴이어야 함).
  • 쉘 문자열 조작을 사용하면 먼저 첫 번째 항목 이전의 모든 항목을 삭제한 _다음 두 번째 단계에서는 마지막 항목부터 시작하는 모든 항목을 삭제합니다 _.
  • 우리는 다음과 같은 방법으로 결과를 출력합니다 printf. (Stéphane Chazelas가 지적했듯이 쉘에 이 명령이 누락될 가능성은 거의 없습니다.)

최종 출력은 유일한 출력이 아닙니다. 중복을 제거하기 위해 출력을 파이프합니다 sort -u.

노트당신이 말한 대로 이 패턴과 일치하는 파일이 많으면 for루프 매개변수 목록이 셸의 내부 제한을 초과할 수 있습니다. 또한 이 방법은 파일 이름의 특수 문자와 관련된 많은 함정을 방지하지만 파일 이름에 개행 문자(많은 파일 시스템에서 파일 이름에 유효한 문자)가 포함된 경우 이 방법이 실패함을 의미합니다 printf.sort

답변2

그리고 zsh:

typeset -U groups=( **/*_*_*.*(Ne['REPLY=${${(s[_])REPLY:t}[2]}']) )
  • typeset -U groups=(...): 고유한 멤버가 있는 groups배열 로 정의됨U
  • **/*_*_*.*: 파일 이름의 맨 오른쪽, 현재 작업 디렉터리 또는 그 아래에 .s가 1개 이상, 2개 이상이 있습니다._.
  • (Ne['code']):glob 한정자는 glob을 추가로 한정합니다.
  • N: Nulglob: 일치하는 항목이 없으면 비어 있도록 확장합니다.
  • e['code']각 글로브를 1( $REPLYin code) 로 확장하여 변환합니다.
  • $REPLY:t: t파일의 ail(기본 이름)입니다.
  • ${(s[_])var}: 분할 _(그런 다음 로 두 번째 작업을 수행합니다 [2]).

bash(GNU 쉘), GNU find및 GNU를 사용하면 awk다음과 같은 작업을 수행할 수 있습니다.

readarray -td '' groups < <(
  LC_ALL=C find . -name '.?*' -prune -o \
    -name '*_*_*.*' -printf '%f\0' |
    gawk -v RS='\0' -v ORS='\0' -F _ '!seen[$2]++ {print $2}'
)

이는 처음 두 문자 사이에 어떤 문자 또는 문자가 아닌 문자가 있는지에 대한 가정을 하지 않습니다 _.

둘 다 숨겨진 파일과 숨겨진 디렉터리의 파일을 건너뜁니다. 이를 포함하려면 Din 에 glob 한정자를 추가 zsh하거나 -name '.?*' -prune -oin 을 제거하세요 find.

파일 목록이 큰 경우 find- 기반 파일은 전체 목록을 메모리에 저장하지 않으므로 메모리 친화적입니다. 비슷한 접근 방식을 취할 수 있습니다 zsh.

typeset -A seen=()
: **/*_*_*.*(Ne['! seen[${${(s[_])REPLY:t}[2]}]='])
groups=( ${(k)seen} )

¹ 이 코드의 종료 상태에 따라 파일이 선택되었는지 여부도 결정되지만 이 코드는 항상 true를 반환합니다.

답변3

답변을 얻는 동안 해결책도 찾았습니다. @AdminBee도 언급했듯이:

find파일 시스템의 방대한 결과 목록에서 xargs검색 패턴을 제한할 수 없는 경우(예: "*.txt")를 사용하도록 선택할 수 있습니다.

for f in ./some/path/*.txt; do gr=${f#*_};gr=${gr%_*}; echo "$gr"; done | sort -u
> ABC
> XYZ

find ./ -iname '*.txt' | xargs -n 1 | cut -d '_' -f 2 | sort -u
> ABC
> XYZ

관련 정보