find . -type d
通常は表示されます
./dir1
./dir1/dir2
./dir3
./dir3/dir4
./dir3/dir4/dir5
...
私はただ
./dir1/dir2
./dir3/dir4/dir5
、親 ./dir1 なし、...
つまり、サブディレクトリが含まれないディレクトリのみを表示したいのです。
何か案が?
編集:-links 2
通常のLinux環境では動作することがわかりました。
docker run -it --rm ubuntu:bionic find /etc -type d -links 2
完璧に動作します。
ただし、ディレクトリ (MacOS または Windows から) を Docker コンテナーにマウントすると、状況が変わり、機能しなくなります。次の操作を試してください。
docker run -it --rm -v /etc:/etc_of_host ubuntu:bionic find /etc_of_host -type d -links 2
答え1
とzsh
:
has_subdirs() () (( $# )) ${1-$REPLY}/*(ND/Y1)
print -rC1 -- **/*(ND/^+has_subdirs)
または、仲介機能を使わずに直接:
print -rC1 -- **/*(ND/^e['()(($#)) $REPLY/*(ND/Y1)'])
それは:
fn() some-command
Bourne シェルやほとんどの Bourne 系シェルと同様に、 を本体とするfn
関数を定義します。some-command
() { code } args
位置パラメータとして実行さcode
れる匿名関数。args
(( $# ))
ここで、その無名関数の本体は、次のように解決される算術式である。真実$#
(引数の数)がゼロ以外の場合。${param-default}
(Bourne シェルより)は$param
、パラメータが設定されている場合は に展開され、default
そうでない場合は に展開されます。ここで を使用すると、関数を直接 ( として) 呼び出すことも、以下のようにグロブ修飾子関数として${1-$REPLY}
呼び出すこともできます。has_subdirs mydir
$dir/*(ND/Y1)
は、隠しファイルも含め$dir
( )内のディレクトリ タイプのファイルに展開され( otglob)、一致しない場合はエラーになりません ( ullglob)。ただし、 の場合は、最初の一致で停止します。したがって、匿名関数 (および) は、ディレクトリに少なくとも 1 つのサブディレクトリが含まれている場合に true を返します。/
D
N
Y1
has_subdirs
print -rC1
引数r
awを1
C
列に出力します^+has_subdirs
関数が true を返さないファイルに制限しますhas_subdirs
(^
)。
シェルを使用する必要がある場合はbash
、次のようにします。
zsh << 'EOF'
print -rC1 -- **/*(ND/^e['()(($#)) $REPLY/*(ND/Y1)'])
EOF
または、結果を bash 配列に保存するには、次のようにします (bash-4.4 以降が必要です)。
readarray -td '' array < <(zsh << 'EOF'
print -rNC1 -- **/*(ND/^e['()(($#)) $REPLY/*(ND/Y1)'])
EOF
)
(任意のパスを保存できるように NUL で区切られたレコードを使用します)。
を持っていなくてzsh
も、 を持っている場合はperl
、次のようにします。
find . -depth -type d -print0 |
perl -l -0ne 'print if rindex $prev, "$_/", 0; $prev = $_'
あるいはGNUをお持ちの場合awk
:
find . -depth -type d -print0 |
gawk -v 'RS=\0' 'index(prev, $0"/") != 1; {prev = $0}'
それらはfind
ディレクトリを印刷します深さ優先(ブランチの前に残ります)、perl
/ を取得してawk
、見つからないレコードを出力し、その後に/
前のレコードの先頭を出力します。
-l
繰り返しになりますが、ファイルを bash 4.4 以降の配列に保存するには、 の後に を-0
移動するperl
か を追加して、-v 'ORS=\0'
出力時に NUL 区切りのレコードに切り替える必要がありますgawk
。
readarray -td array < <(
find . -depth -type d -print0 |
perl -0lne 'print if rindex $prev, "$_/", 0; $prev = $_'
)
readarray -td array < <(
find . -depth -type d -print0 |
gawk -v 'RS=\0' -v 'ORS=\0' 'index(prev, $0"/") != 1; {prev = $0}'
)
一部のシステムおよびファイル システム (Linux ベースのシステム上のファイル システムなど) では、サブディレクトリを持つディレクトリのリンク数が 2 より大きい ( 、および ごとに追加のリンク)ext4
という事実に依存できる場合があります。dir
dir/.
dir/subdir/..
print -rC1 -- **/*(ND/l-3)
またはfind
任意のシェルで使用します:
find . -type d -links -3
btrfs
これは、たとえばディレクトリのリンク数が常に 1 である(いくつかの Linux ディストリビューションでデフォルトのファイルシステムとして置き換えられている) 場合には機能しないext4
ため、一般的な解決策としてはお勧めしません。
overlayfs
ユニオンファイルシステムの場合も同様です。合併したディレクトリには、サブディレクトリが含まれているかどうかに関係なく、リンク カウントが 1 になります。
ただし、使用可能な場合は、ディレクトリへの読み取りアクセスを必要としない (親への検索アクセスのみを必要とする) サブディレクトリを手動でカウントするソリューションよりも利点があります。
答え2
あなたが探しているのは次のものです:
find . -type d -links 2
ファイルシステム内の各ディレクトリには、少なくとも 2 つのハード リンク (親ディレクトリ自体と '.' エントリ) があります。サブディレクトリ内の各 '..' エントリは、ディレクトリに新しいハード リンクを追加します。したがって、2 つのハード リンクを持つディレクトリを見つけるだけで済みます。
別の回答で提案されたコマンド
find . -type d -links -3
同じことを行いますが、「ハード リンクが 3 つ未満のディレクトリ」というステートメントを使用します。
答え3
最もソートされたもの:
p="";(find . -type d;echo) | while read d; do [[ $p && $d != $p/* ]] && echo $p; p=$d; done
一行で
a="";(find . -type d;echo )|while read i; do if [[ (! $i =~ $a) && ("$a" != "") ]]; then echo $a; fi; a=$i;done
投稿者が述べたように:
a="";(find . -type d;echo )|while read i; do [[ $i != $a/* && ! -z "$a" ]] && echo $a; a=$i;done
答え4
読んでくださいman find
。-mindepth
オプションはあなたが望むものです。