폴더 목록이 있는데 대부분의 폴더 이름이 어떤 폴더 이름으로 시작하는지 알고 싶습니다.
다음 폴더 목록이 주어지면:
./
./.something
./unrelated
./Target.Dire ctoryName
./Target.Dire ctoryNameOther
./Target.Dire ctoryName.Other
./Target.Dire ctoryName.Stuff
./Target.Dire ctoryName.Stuff.Other
./Unrelated.Dire ctoryName
./Unrelated.Dire ctoryNameStuff
./Unrelated.Dire ctoryName.Stuff
./Unrelated.Dire ctoryName.Other
./More.Unrelated.Dire ctoryName
./More.Unrelated.Dire ctoryName.Other
./Target.Dire ctoryName
이름(공백 포함)을 알고 싶습니다 .
나는 이것을 생각해 냈지만 숨겨진 폴더를 제외하고 매우 길고 "다음으로 시작"을 수행하지 않고 "포함"을 수행합니다.
find * -maxdepth 0 -type d | xargs -d $'\n' sh -c \
'for arg do find * -maxdepth 0 -type d | grep -wo "$arg"; done' _ \
| sort | uniq -c | sort -nr | head -1 | echo "./$(awk '{print $2}')"
숨겨진 폴더가 있는 버전과 없는 버전의 두 가지 버전이 있을 수 있습니다. 내 사용 사례에서는 find * -maxdepth 0 -type d
모든 잠재적 폴더가 포함됩니다.
폴더 이름이 필요한 이유는 내가 사용하는 도구가 특정 매개변수와 함께 사용될 때 "target/home" 디렉터리를 파악할 수 없기 때문입니다.
답변1
를 사용하면 zsh
다음을 수행할 수 있습니다.
all=(*(N/)) max=0 best=
for dir ($all) (){ (( $# > max )) && max=$# best=$dir; } ${(M)all:#$dir*}
print -r -- $max $best
*(N/)
유형으로 확장되는 숨김 되지 않은 파일목차현재 디렉토리(또는 ullglob 한정자와 일치하지 않는 경우 아무것도 없음 N
).
${(M)all:#$dir*}
패턴과 일치하는 배열 요소로 확장됩니다 $all
. 즉, 이 값은 익명 함수( )에 인수로 전달되어 최대값과 비교됩니다.M
$dir*
$dir
(){....}
동일한 상황이 발생하면 어휘순으로 정렬된 디렉터리 목록에서 첫 번째 디렉터리를 선택합니다( 마지막 디렉터리를 얻으려면 >
로 바꾸십시오).>=
숨겨진 디렉터리를 포함하려면( 항상 제외하려면) glob 한정자( )를 추가 D
하세요 .dotglob
all=(*(ND/))
.
..
아래는 원래 답변입니다. 요구 사항을 너무 빨리 읽었습니다. 디렉터리 자체의 이름이 아니더라도 해당 디렉터리에 대한 가장 일반적인 공통 접두사를 찾습니다. 예를 들어, between , ab1
및 대신 다음을 반환 ab2
ab3
합니다 .bc
bc1
ab
bc
typeset -A c
for f (*(/)) for ((i=1;i<=$#f;i++)) ((c[\$f[1,i]]++))
printf -v argv '%2$08d%1$s' ${(kv)c}
print -r -- ${${(O)@}[1][9,-1]}
*(/)
유형으로 확장되는 숨김 되지 않은 파일목차현재 디렉터리에 있습니다(그렇지 않으면 오류와 함께 중단됩니다).
그런 다음 연관 배열을 구축하여 $c
이러한 디렉터리 이름에 대해 가능한 각 접두사의 발생 횟수를 기록합니다.
그런 다음 발생 횟수를 기준으로 배열을 구성하고 0부터 8자리까지 채운 다음 $argv
각 접두사에 대한 접두사를 추가합니다.$@
그런 다음 O
해당 배열을 어휘 역순으로 정렬하므로 첫 번째 배열이 가장 많이 발생하는 배열이 되고, 동률이 있으면 마지막 배열이 정렬됩니다(가장 긴 접두사도 제공됨).
그런 다음 첫 번째 문자( )를 선택하고 [1]
9번째 마지막 문자( )를 인쇄합니다.[9,-1]
숨겨진 디렉터리를 포함하려면 ( 한정자 에 추가) *(/)
로 바꾸세요 . 포함되지 않았습니다 .*(D/)
D
dotglob
.
..
답변2
순수 bash에서 이 작업을 수행하는 방법을 잘 모르겠지만 아래 Python 스크립트는 가능한 모든 폴더 이름에 대해 작동해야 합니다. 또한 명령줄 인수도 허용합니다(아래에서 나중에 설명).선택적 패턴 일치 매개변수).
#!/usr/bin/env python3
import subprocess
import sys
if len(sys.argv) == 1:
folder = subprocess.run(\
['find','-mindepth','1','-maxdepth','1','-type','d','-print0'],\
capture_output=True).stdout[:-1].split(b'\x00')
else:
folder = subprocess.run(\
['find','-mindepth','1','-maxdepth','1','-type','d',\
'-name',sys.argv[1], '-print0'],\
capture_output=True).stdout[:-1].split(b'\x00')
counts = []
for name in folder:
counts.append(sum(name in i[:len(name)] for i in folder))
counts = sorted(list(zip(counts,folder)),reverse=True)
if counts[0][0]>1:
sys.stdout.buffer.write(counts[0][1]+b'\x0a')
스크립트를 mainfoldername.py
다른 이름으로 저장하면 명령은 python3 /path/to/mainfoldername.py
현재 작업 디렉터리에서 폴더 이름의 시작 문자열로 가장 자주 발생하는 기준을 충족하는 폴더 이름을 출력합니다. 이 조건을 충족하는 폴더가 없으면 스크립트는 출력을 생성하지 않습니다.
제공한 예제 디렉토리를 사용하면 python3 /path/to/mainfoldername.py
출력은 다음과 같습니다../Target.Dire ctoryName
.
사용명령 확장, 변수는 스크립트의 출력 값으로 설정되어 다른 명령에 사용될 수 있습니다.
$ myvar="$( python3 /path/to/mainfoldername.py )"
$ echo "$myvar"
./Target.Dire ctoryName
$ cd "$myvar"
Target.Dire ctoryName$
쉘 스크립트 사용
존재하다쉘 스크립트이 출력이 사용되며 기준을 충족하는 폴더 이름이 없는 경우(예: Python 스크립트가 출력을 생성하지 않는 경우) 길이가 0인 값을 테스트하여 확인해야 합니다. 예:
#!/bin/sh
myvar="$( python3 /path/to/mainfoldername.py )"
[ ! -z "$myvar" ] || exit 1
선택적 패턴 일치 매개변수
python3 /path/to/mainfolder.py PATTERN
스크립트는 명령줄에서 선택적 인수를 허용합니다.PATTERN
폴더 이름이 일치해야 하는 쉘 패턴입니다.
가장 기본적인 용도는 일반 폴더 찾기와 숨겨진 폴더 찾기 사이를 전환하는 것입니다. 이 스크립트의 기본 동작은 모든 폴더를 찾는 것입니다.
숨겨진 폴더만 찾기, 사용'.*'
~을 위한PATTERN
:
python3 /path/to/mainfolder.py '.*'
숨겨지지 않은 폴더만 찾기, 사용'[!\.]*'
python3 /path/to/mainfolder.py '[!\.]*'
대상 폴더 이름에 나타날 특정 문자열을 알고 있는 경우에도 유용합니다.
이름에 이 문자열이 포함된 폴더만 찾기Target
:
python3 /path/to/mainfolder.py '*Target*'
셸에 의한 확장을 방지하려면 패턴을 항상 따옴표로 묶어야 합니다. 바라보다"쉘 패턴 매칭"더 많은 정보를 알고 싶습니다.
답변3
다음 awk
프로그램은 가장 자주 발생하는 디렉터리 경로를 입력의 모든 디렉터리 경로에 대한 접두사로 출력합니다.
디렉토리 경로는 한 번에 한 줄씩 나타나고 경로 이름에는 개행 문자가 포함되어 있지 않다고 가정합니다.
{ sub("/$",""); count[$0] = 0 }
END {
for (p1 in count)
for (p2 in count) {
count[p2] += (index(p1,p2) == 1)
if (count[p2] > m) {
m = count[p2]
p = p2
}
}
print p
}
이는 입력의 각 줄을 읽고 이를 연관 배열의 키로 저장합니다 count
. /
먼저 후행을 제거하십시오.
모든 입력을 읽었으면 저장된 키를 쌍으로 비교하고 각 키가 다른 키 내의 하위 문자열로 나타나는 횟수를 계산합니다. 에서 가장 자주 발생하는 경로 이름 p
과 에서 발생하는 횟수를 추적합니다 m
.
이 호출은 index(p1,p2)
문자열에서 발생이 발생한 위치 p1
( p2
또는 발생이 전혀 없는 경우 0)를 반환하며 결과가 숫자 1( p2
시작 부분에서 발생 p1
)인 경우에만 관심이 있습니다.
위 프로그램은 다음과 같이 명령줄에서 인라인으로 작성할 수도 있습니다.
awk '{ sub("/$",""); c[$0]=0 } END { for (a in c) for (b in c) { c[b]+=(index(a,b)==1); if (c[b]>m) { m=c[b]; p=b } } print p }'
이에 대한 입력으로 다음을 사용할 수 있습니다.
printf '%s\n' ./*/
( 쉘 dotglob
에서 활성화하면 숨겨진 디렉토리 이름을 얻을 수도 있습니다.)bash
결국, 당신은 다음과 같은 것을 얻게 될 것입니다
shopt -s dotglob
printf '%s\n' ./*/ | awk -f script
awk
(또는 대신 더 긴 인라인 스크립트를 사용하십시오 -f script
.)
시험:
$ ls -FA
.something/ Unrelated.Dire ctoryName/
Target.Dire ctoryName/ Unrelated.Dire ctoryName.Other/
Target.Dire ctoryName.Other/ Unrelated.Dire ctoryName.Stuff/
Target.Dire ctoryName.Stuff/ Unrelated.Dire ctoryNameStuff/
Target.Dire ctoryName.Stuff.Other/ script
Target.Dire ctoryNameOther/ unrelated/
$ shopt -s dotglob
$ printf '%s\n' ./*/ | awk -f script
./Target.Dire ctoryName
답변4
C# 스크립트
이것은C# 스크립트:
#!/usr/bin/env dotnet-script
var dirs = Directory.GetDirectories(".");
Console.Write(dirs.MaxBy(d => dirs.Count(x => x.StartsWith(d))));
디렉터리에서 를 실행합니다 dotnet script /path/to/mainfoldername.csx
.