질문
- 나는 디렉터리를 재귀적으로 검색한 다음 고유한 숨겨진 파일 및/또는 숨겨진 디렉터리의 모든 하위 디렉터리(최대 깊이까지)가 포함된 경로를 반환할 수 있는 Bash 명령을 작성하려고 했습니다.
시각적 설명
- 다음 파일 시스템 발췌문을 고려하십시오.
+--- Root_Dir
| +--- Dir_A
| | +--- abc.txt
| | +--- 123.txt
| | +--- .hiddenfile
| | +--- .hidden_dir
| | | +--- normal_sub_file_1.txt
| | | +--- .hidden_sub_file_1.txt
| |
| +--- Dir_B
| | +--- abc.txt
| | +--- .hidden_dir
| | | +--- normal_sub_file_2.txt
| | | +--- .hidden_sub_file_2.txt
| |
| +--- Dir_C
| | +--- 123.txt
| | +--- program.c
| | +--- a.out
| | +--- .hiddenfile
| |
| +--- Dir_D
| | +--- .hiddenfile
| | +--- .another_hiddenfile
| |
| +--- Dir_E
| | +--- .hiddenfile
| | +--- .hidden_dir
| | | +--- normal_sub_file_3.txt # This is OK because its within a hidden directory, aka won't be checked
| | | +--- .hidden_sub_file_3.txt
| |
| +--- Dir_F
| | +--- .hidden_dir
| | | +--- normal_sub_file_4.txt
| | | +--- .hidden_sub_file_4.txt
원하는 출력
- 내가 찾고 있는 명령이 출력됩니다.
./Root_Dir/Dir_D ./Root_Dir/Dir_E ./Root_Dir/Dir_F
Dir_D
숨겨진 파일만 포함되어 있기 때문입니다.Dir_E
내가 찾고 있는 레벨에 대한 숨겨진 파일과 숨겨진 디렉터리만 포함되어 있기 때문입니다.Dir_F
내가 찾고 있는 레벨에 대한 숨겨진 디렉토리만 포함되어 있기 때문입니다.
노력하다
- 해당 명령을 사용하여
find
원하는 결과를 얻으려고 하는데 출력을 파이프하는 데 필요한 다른 명령이 무엇인지 또는 사용해야 하는 다른 옵션이 무엇인지 알 수 없는 것 같습니다. - 유효한 명령은 다음과 같습니다.
bob@linux:/$ find ./Root_Dir -mindepth 2 -maxdepth 2 -type d -name "*." -type -f -name "*." | command to see if these are the only files in that directory
답변1
나는 이것에 대해 그다지 좋지 않은 해결책을 가지고 있습니다.
스크립트 형식:
#!/bin/bash
# Echo whatever is passed to fail, and then exit with a status of 1
fail() {
echo >&2 "$@"
exit 1
}
# If the number of arguments are less or more than what
# we expect, throw help syntax and exit.
if [ $# -gt 2 ] || [ $# -lt 2 ]
then
fail "
$0 check for directories that only contain hidden listings
Usage: $0 <Directory to search from> <Depth to check>
"
fi
# Assign parameters
root_dir=$1
depth=$2
# Find a list of directories that contain files OR subdirectories
# that are hidden
readarray -t dirs < <(export LC_ALL=C
find "$root_dir" -mindepth "$depth" -maxdepth "$depth" \
-name ".*" \( -type d -o -type f \) -execdir pwd \; | sort -u
)
# Of the dirs we found, do any of them return any listings with a
# default ls execution? If so, that directory cannot only contain
# hidden listings.
final=()
for dir in "${dirs[@]}"
do
notExclusive="$(ls -- "$dir")"
if [ "$notExclusive" = "" ]
then
final+=("$dir")
fi
done
# The array final contains the directories who only contain hidden
# files/subdirectories.
printf '%s\n' "${final[@]}"
기본적으로 우리는 숨겨진 목록(질문에 지정된 깊이 2)이 포함된 디렉터리를 찾아 배열에 로드하고 ls
플래그가 아무 것도 반환하지 않으면 디렉터리에 숨겨진 목록만 포함되어 있어 표준을 충족한다고 결론을 내릴 수 있습니다.
find
OP에 대한 설명을 바탕으로 한 번만 호출하면 되는 이유를 설명하세요 . 명령 find
에는 기본 논리에 대한 연산자가 있습니다. -a는 논리 AND에서 두 표현식을 결합할 때의 기본 동작입니다. 논리 NOT에서는 -o는 논리 OR에서와 같습니다.
이 방법은 디렉터리 경로에 개행 문자가 포함되어 있지 않다고 가정하고, 포함된 경우 readarray
각 디렉터리 경로를 잘못 구분합니다.
추악한 "한 줄":
readarray -t dirs < <(export LC_ALL=C; find ./Root_Dir -mindepth 2 -maxdepth 2 -name '.*' \( -type d -o -type f \) -execdir pwd \; | sort -u); final=(); for dir in "${dirs[@]}"; do notExclusive="$(ls -- "$dir")"; if [ "$notExclusive" = "" ]; then final+=("$dir"); fi; done; printf '%s\n' "${final[@]}"
답변2
find
및 를 사용하여 bash
다음 명령은 모든 디렉터리를 찾습니다. 그런 다음 bash
발견된 디렉터리에 숨겨지지 않은 이름이 포함되어 있는지 여부를 테스트 하는 데 사용됩니다 . 이는 *
각 디렉터리의 glob 패턴을 확장하고 결과 이름 수를 계산하여 수행됩니다. 숫자가 0이면 출력 디렉터리의 경로 이름이 출력됩니다. 기본적으로 전역 모드는 *
숨겨진 이름으로 확장되지 않습니다.
find . -type d -exec bash -O nullglob -c '
for dirpath do
set -- "$dirpath"/*
[[ $# -eq 0 ]] && printf "%s\n" "$dirpath"
done' bash {} +
일치하는 항목이 없으면 패턴 자체를 제거하도록 nullglob
인라인 스크립트에 셸 옵션을 설정 했습니다 .bash -c
를 사용하면 셸 옵션 /bin/sh
에 액세스할 수 없으므로 nullglob
패턴이 확장되는 개별 이름이 실제로 존재하는지 테스트해야 합니다. 그렇지 않은 경우 디렉터리에는 숨겨진 이름만 포함됩니다.
find . -type d -exec sh -c '
for dirpath do
set -- "$dirpath"/*
[ "$#" -eq 1 ] && [ ! -e "$1" ] && printf "%s\n" "$dirpath"
done' sh {} +
발견을 피하고 싶다면비어 있는디렉토리는 ! -empty
홈 디렉토리 앞에 추가됩니다(귀하의 구현이 일반적인 테스트를 통해 이 비표준을 지원한다고 가정).-exec
find
find
답변3
그리고 zsh
:
print -rC1 -- **/*(NDF^e['()(($#)) $REPLY/*(NY1)'])
특정 깊이 이상의 디렉터리를 제외하려면 ~
제외 연산자를 사용하여 제외할 수 있습니다.
set -o extendedglob
print -rC1 -- **/*~*/*/*(NDF^e['()(($#)) $REPLY/*(NY1)'])
zsh
그러나 그것이 먼저 그들 속으로 내려가는 것을 멈추지 않는다는 점에 유의하십시오 .
깊이 2만 원하는 경우 다음을 수행할 수 있습니다.
print -rC1 -- */*(NDF^e['()(($#)) $REPLY/*(NY1)'])
(단, 깊이 1에서는 심볼릭 링크를 따릅니다)
print -rC1
열에r
aw를 인쇄하세요.1
C
**/*
재귀 와일드카드(...)
글로벌 예선N
:N
ulglob: 일치하는 항목이 없어도 불평하지 마세요.D
:D
otglob: 숨겨진 파일을 무시하지 마세요F
: 디렉토리만 비어 있습니다(F
및 를 제외한 하나 이상의 항목)..
..
^
: 다음 한정자를 부정합니다.e['code']
: 파일 선택 여부를e
평가합니다 .code
()(($#)) args
: 하나 이상의 매개변수가 전달되면 true를 반환합니다.$REPLY
, 에서code
현재 고려 중인 파일을 저장합니다.$REPLY/*
숨겨지지 않은 파일$REPLY
Y1
: 첫 번째 파일을 찾은 후 중지합니다.