在 Bash 中使用 ls 仅列出目录,但保留 ls 格式且没有 dirname

Listing only directories using ls in Bash but preserve ls format and without dirname

this similar question 已经有很多答案了。但是 none 满足我的要求。我要

  1. 列出一个目录下的所有目录,不用glob(*)语法,即我想直接用lsdir somedir

  2. 输出应包含目录的基本名称,就像您使用 ls 时一样,例如:

    $ lsdir path/to/some/dir
    dir1 dir2 dir3 dir4
    

    但不是这个:

    $ lsdir path/to/dir
    path/to/dir/dir1 path/to/dir/dir2 path/to/dir/dir3 path/to/dir/dir4
    

    为了满足要求 1,定义一个函数似乎是可行的,但无论如何我们将使用 -d 选项,列出 ls 命令参数的目录本身。

    并且在使用 -d 选项时,ls 列出目录名称并在其父目录前加上前缀,如上所示。

  3. ls 格式(颜色、对齐、排序)应保留。

    为了满足要求 2,我们可以使用 find 但这样我们就失去了所有 ls 输出格式,比如着色(基于自定义的 dircolors 主题)、对齐(输出对齐列)、排序(使用各种标志和列优先方式自定义排序),也许还有其他一些东西。

我知道同时想要这么多功能太贪心了,事实上我可以没有所有这些功能。

可以手动模拟 ls 输出格式,但这太不一致了。

我想知道是否有办法实现这一点并仍然利用 ls,即如何使用 ls.

实现要求 2

这可能是您要找的:

cd path/to/dir && dirs=(*/) && ls -d "${dirs[@]%?}"

或者,也许

(shopt -s nullglob; cd path/to/dir && dirs=(*/) && ((${#dirs[@]} > 0)) && ls -d "${dirs[@]%?}")

第二个版本在子 shell 中运行,如果 path/to/dir.

中没有任何子目录,则不打印任何内容

基于@M。 Nejat Aydin 的出色回答,我将进一步改进使其成为一个有用的命令,尤其是在处理选项和多个目录方面。

list_directories() {
  local opts=()
  local args=()
  for i in $(seq $#); do
    if [[ "${!i}" == -* ]]; then
      opts+=("${!i}")
    else
      args+=("${!i}")
    fi
  done
  (( ${#args[@]} == 0 )) && args=('.')
  local -i args_n_1=${#args[@]}-1
  for i in $(seq 0 $args_n_1); do
    if (( ${#args[@]} > 1 )); then
      (( i > 0 )) && echo
      echo "${args[i]}:"
    fi
    (
      shopt -s nullglob 
      cd "${args[i]}" && 
      dirs=(*/) && 
      (( ${#dirs[@]} > 0 )) && 
      ls -d "${opts[@]}" "${dirs[@]%?}" 
    )
  done
}
alias lsd=list_directories

lsd 可与任意数量的 ls 选项和目录自由混合使用。

$ lsd -h dir1 dir2 -rt ~

注意:当您将 glob 与 lsd 一起使用时,语义会发生变化。

lsd path/to/dir* 列出以“path/to/dir”开头的每个目录下的所有目录。
要列出所有以“path/to/dir”开头的目录,请使用普通的 ls -d path/to/dir*.