UNIX 命令树可以只显示匹配模式的目录吗?

slm*_*slm 2 command-line shell tree

我想弄清楚是否有办法让 UNIX 命令tree仅显示与特定模式匹配的目录。

% tree -d tstdir -P '*qm*' -L 1
tstdir
|-- d1
|-- d2
|-- qm1
|-- qm2
`-- qm3

5 directories
Run Code Online (Sandbox Code Playgroud)

男子页显示了这个位有关交换机。

-P 模式只列出那些匹配通配符模式的文件。注意:您必须使用 -a 选项来考虑以点.' for matching. Valid wildcard operators are*'(任何零个或多个字符)、?' (any single character),[...]'(括号之间列出的任何单个字符(可选 - (破折号)表示字符范围)开头的文件可以使用:例如:[AZ]) 和[^...]' (any single character not listed in brackets) and|' 分隔替代模式。

我假设关于......只列出那些文件......是问题所在。我的解释是否正确,这个开关只会在文件而不是目录上进行模式匹配?

编辑#1

@f-hauri看起来有最好的理由来说明为什么这不像人们从tree手册页中可用的开关所想到的那样工作。我在 BUGS 部分错过了这一点。

BUGS
   Tree  does not prune "empty" directories when the -P and -I options are
   used.  Tree prints directories as it comes to them, so  cannot  accumu?
   late  information  on files and directories beneath the directory it is
   printing.
Run Code Online (Sandbox Code Playgroud)

鉴于此限制,它看起来tree不是完成包含过滤列表的最佳方法,但排他过滤列表将是使用-Iswitch的另一种方法。

取而代之的是,它看起来像 shell 通配符、find 命令或 Perl 脚本将是完成此操作的更合适的方法。有关这些替代方法中的一些,请参阅@f-hauri 的好答案。

F. *_*uri 5

是的,这是一个错误。从手册页:

BUGS
   Tree  does not prune "empty" directories when the -P and -I options are
   used.  Tree prints directories as it comes to them, so  cannot  accumu?
   late  information  on files and directories beneath the directory it is
   printing.
Run Code Online (Sandbox Code Playgroud)

...完全,-d切换询问打印文件:

    -d     List directories only.
Run Code Online (Sandbox Code Playgroud)

所以如果你想使用它,你可以:

tree tstdir -P '*qm*' -L 1 | grep -B1 -- '-- .*qm'
|-- id1
|   `-- aqm_P1800-id1.0200.bin
--
|-- id165
|   `-- aqm_P1800-id165.0200.bin
|-- id166
|   `-- aqm_P1800-id166.0200.bin
--
|-- id17
|   `-- aqm_P1800-id17.0200.bin
--
|-- id18
|   `-- aqm_P1800-id18.0200.bin
--
|-- id2
|   `-- aqm_P1800-id2.0200.bin
Run Code Online (Sandbox Code Playgroud)

总之,如果你使用-L 1

   -L level
          Max display depth of the directory tree.
Run Code Online (Sandbox Code Playgroud)

你可以更好地使用(在 bash 中)这个语法:

cd tstdir
echo */*qm*
Run Code Online (Sandbox Code Playgroud)

或者

printf "%s\n" */*qm*
Run Code Online (Sandbox Code Playgroud)

如果只需要 dir:

printf "%s\n" */*qm* | sed 's|/.*$||' | uniq
Run Code Online (Sandbox Code Playgroud)

总之,如果纯 bash,您可以非常快速地完成此操作:

declare -A array;for file in  */*qm* ;do array[${file%/*}]='';done;echo "${!array[@]}"
Run Code Online (Sandbox Code Playgroud)

这可以解释:

cd tstdir
declare -A array          # Declare associative array, (named ``array'')
for file in  */*qm* ;do   # For each *qm* in a subdirectory from there
    array[${file%/*}]=''  # Set a entry in array named as directory, containing nothing
  done
echo "${!array[@]}"         # print each entrys in array.
Run Code Online (Sandbox Code Playgroud)

...如果没有文件匹配模式,结果将显示*. 所以为了完美的工作,还有剩下的事情要做:

resultList=("${!array[@]}")
[ -d "$resultList" ] || unset $resultList
Run Code Online (Sandbox Code Playgroud)

(这将比

declare -A array
for file in  */*qm*; do
    [ "$file" == "*/*qm*" ] || array[${file%/*}]=''
  done
echo "${!array[@]}"
Run Code Online (Sandbox Code Playgroud)

)