質問

質問

質問

  • 私はディレクトリを再帰的に検索し、一意の隠しファイルおよび/または隠​​されたディレクトリのすべてのサブディレクトリ(最大深度まで)を含むパスを返すことができる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で2つの式を結合するときのデフォルトの動作です。論理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
  • **/*再帰ワイルドカード
  • (...)グローバル予選
  • NNulglob:一致するものがなくても文句を言わないでください。
  • DDotglob:隠しファイルを無視しないでください
  • F:ディレクトリのみが空です(Fおよびを除く1つ以上のエントリ)。...
  • ^:次の修飾子を否定します。
  • e['code']:ファイルを選択するかどうかをe評価します。code
  • ()(($#)) args:1つ以上のパラメータが渡された場合はtrueを返します。
  • $REPLYcode現在検討中のファイルを保存します。
  • $REPLY/*隠されていないファイル$REPLY
  • Y1:最初のファイルを見つけて停止します。

関連情報