질문

질문

질문

  • 나는 디렉터리를 재귀적으로 검색한 다음 고유한 숨겨진 파일 및/또는 숨겨진 디렉터리의 모든 하위 디렉터리(최대 깊이까지)가 포함된 경로를 반환할 수 있는 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플래그가 아무 것도 반환하지 않으면 디렉터리에 숨겨진 목록만 포함되어 있어 표준을 충족한다고 결론을 내릴 수 있습니다.

findOP에 대한 설명을 바탕으로 한 번만 호출하면 되는 이유를 설명하세요 . 명령 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홈 디렉토리 앞에 추가됩니다(귀하의 구현이 일반적인 테스트를 통해 이 비표준을 지원한다고 가정).-execfindfind

답변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열에 raw를 인쇄하세요.1 C
  • **/*재귀 와일드카드
  • (...)글로벌 예선
  • N: Nulglob: 일치하는 항목이 없어도 불평하지 마세요.
  • D: Dotglob: 숨겨진 파일을 무시하지 마세요
  • F: 디렉토리만 비어 있습니다( F및 를 제외한 하나 이상의 항목)....
  • ^: 다음 한정자를 부정합니다.
  • e['code']: 파일 선택 여부를 e평가합니다 .code
  • ()(($#)) args: 하나 이상의 매개변수가 전달되면 true를 반환합니다.
  • $REPLY, 에서 code현재 고려 중인 파일을 저장합니다.
  • $REPLY/*숨겨지지 않은 파일$REPLY
  • Y1: 첫 번째 파일을 찾은 후 중지합니다.

관련 정보