特定のパスのサブディレクトリを一覧表示する必要があります。区切りは改行文字ではなく空白でなければなりません。
また、サブディレクトリへの絶対パスは望ましくなく、その名前のみが必要です。
# correct
dir1 dir2 dir3
# incorrect: separation with new lines
dir1
dir2
dir3
# incorrect: absolute paths
/home/x/y/dir1 /home/x/y/dir2 /home/x/y/dir3
他の記事もたくさん見ましたが、この投稿しかし、彼らは私の要求を満たしていません。
私はこれを試しましたが、ls -d ~/y
新しい行で区切られた絶対パスをリストします。私はsedを使用してパスから無関係な部分を削除し、すべての新しい行を削除できると思いました。しかし、動作させることはできません。より良い解決策があるはずです。
答え1
GNUツールを使用していると仮定すると、GNUを使用して特定のディレクトリbasename
にあるすべてのサブディレクトリの名前を取得できます。その後、paste
スペースで区切られたリストにフォーマットすることができます。
basename -a /some/path/*/ | paste -d ' ' -s -
上記のコマンドは、GNUがコマンドラインからオペランドとして指定された複数のパス名のうち、ファイル名の部分を返すことができるというbasename
事実を利用します。-a
で終わるファイル一致パターンを使用して/
GNUパス名を生成しますbasename
。ディレクトリのみがこれらのパターンと一致できます。
最後に、paste
GNUで生成された改行で区切られたリストからスペースで区切られたリストを作成しますbasename
。
元のディレクトリ名に空白文字が含まれている場合、結果のファイル名のリストを解析することは困難です。
ディレクトリにシンボリックリンクが含まれている場合、このメソッドはそのシンボリックリンクに従おうとします。
外部ツールの使用を制限するために、シェルの配列を使用してディレクトリbash
パスを保存および操作できます。
shopt -s nullglob
topdir=/some/path
dirpaths=( "$topdir"/*/ )
dirpaths=( "${dirpaths[@]#$topdir/}" )
dirpaths=( "${dirpaths[@]%/}" )
printf '%s\n' "${dirpaths[*]}"
上記のシェルコードは、この回答の最初の部分で使用したのと同じワイルドカードパターンを拡張しますが、結果のディレクトリパスを配列に保存しますdirpaths
。次に、$topdir/
配列の各要素とそれに続く要素から既知の接頭辞を削除し、配列を/
スペースで区切られた名前の単一の文字列として印刷します。最後の行の名前の間に使用される区切り文字は、デフォルトでは空白の$IFS
最初の文字です。
を使用すると、find
最上位ディレクトリ自体が返されないようにしながら、関心のある特定の最上位ディレクトリ内のサブディレクトリを見つけることができます。また、サブディレクトリの入力も停止しますfind
。
topdir=/some/path
find "${topdir%/}/." ! -name . -prune -type d -exec basename {} \; | paste -d ' ' -s -
上記のコマンドは開始点の検索を避けるためにネガティブテストを使用し、-name
検索ツリーをクリーンアップしてサブディレクトリに繰り返さないようにします-prune
。見つかった各ディレクトリをfind
呼び出して、basename
ディレクトリのファイル名を別々の行に出力します。最後のステップにfind
結果をパイプして、paste
1行にスペースで区切られたリストとして出力形式を指定します。
GNUでは、find
次のように書くことができます。
find /some/path -mindepth 1 -maxdepth 1 -type d -printf '%f\n' | paste -d ' ' -s -
このように使用すると、find
隠された名前のディレクトリが一覧表示され、シンボリックリンクされたディレクトリは表示されません。
シェルでは、zsh
高度なシェルグローブモードを使用してディレクトリのファイル名のみを選択し、一度にすべて印刷できます。
print -r -- /some/path/*(/:t)
/:t
このコマンドは2つの部分で構成され、以前のglobingモードに影響を与えるglob修飾子を使用します/some/path/*
。生成された各パス名のファイル名部分である「尾」を抽出する間、パターンはディレクトリ/
(シンボリックリンクされたディレクトリではなく、その目的のために-/
)のみに一致するようにします。:t
このコマンドは、拡張データ内のエスケープprint -r
シーケンス(たとえば、または)を回避しながら、引数を印刷するためにスペースを区切り文字として使用します。区切られたオプション(シェルの操作にも適用されます)にオペランドを使用すると、glob拡張で作成されたディレクトリ名がで始まってもオプションとして処理されません。\n
\t
--
-
ksh
-
bash
シェルでこれを使用してリストを作成できます。
zsh -c 'print -r -- /some/path/*(/:t)'
答え2
サブディレクトリを一覧表示したいディレクトリが既にわかっているので、次のことができます。
find /home/x/y -maxdepth 1 -type d -printf '%P '
答え3
for
ループの使用に関する提案は次のとおりです。
$ echo "$(for node in $(ls ~/); do if test -d "${node}"; then printf "${node} "; fi; done)"
Desktop Documents Downloads Music Pictures Public Templates Videos
代替用途find
:
$ echo "$(for node in $(find ~/ -mindepth 1 -maxdepth 1 -type d); do printf "$(basename ${node}) "; done)"
.mozilla Videos Pictures Music Documents Public Templates Downloads .gnupg .config .local .cache Desktop
編集する:~についてそれらIFS
説明したように、スペースを含むディレクトリの変数を変更する必要があります。
$ IFS_orig=${IFS}
$ IFS=$'\n'
$ echo "$(for node in $(ls ~/); do if test -d "${node}"; then printf "'${node}' "; fi; done)"
'Desktop' 'Documents' 'Downloads' 'Music' 'My Test' 'Pictures' 'Public' 'Templates' 'Videos'
$ IFS=${IFS_orig}
編集する:最も簡単なオプションは次のようになりますls -d *
。
$ ls -d *
Desktop Documents Downloads Music 'My Test' Pictures Public Templates Videos
また、for
ループではtest
絶対パスまたは相対パスを使用する必要があることを忘れてください。
$ echo "$(for node in $(ls "${HOME}"); do if test -d "${HOME}/${node}"; then printf "'${node}' "; fi; done)"
'Desktop' 'Documents' 'Downloads' 'Music' 'My Test' 'Pictures' 'Public' 'Templates' 'Videos'
答え4
私が受け取った最後のコマンドは次のとおりです。ls -d ~/y/*/ | awk -F/ '{print$5}' | sed 's/ /\\ /' | tr '\n' ' '
ソースは、現在の投稿を削除したユーザーからのものですが、現在のディレクトリでlsを使用していないことを考慮していないため、これを調整しました。また、スペースを含むディレクトリ名にバックスラッシュを追加するようにsedパイプを追加しました。
かなりハードコーディングされており、ディレクトリ内のディレクトリprint$5
でのみ機能します。~