Bash “中的-1是什么?”;ls-1路径“;什么意思?

Bash “中的-1是什么?”;ls-1路径“;什么意思?,bash,shell,glob,ls,Bash,Shell,Glob,Ls,我正在看一些shell代码,它用于获取目录中文件数的计数。内容如下: COUNT=$(ls -1 ${DIRNAME} | wc -l) -1部分是什么意思?我在任何其他问题中都找不到关于这一点的任何信息,只是在目录中传递对文件进行迭代的引用,这不是我所看到的。此外,将其从命令中删除似乎没有效果 COUNT=$(ls -1 ${DIRNAME} | wc -l) …是一种计算目录中文件的错误方法:ls-1告诉ls不要将多个文件放在一行上;确保wc-l将通过计算行数来计算文件数 现在,让我们谈

我正在看一些shell代码,它用于获取目录中文件数的计数。内容如下:

COUNT=$(ls -1 ${DIRNAME} | wc -l)
-1
部分是什么意思?我在任何其他问题中都找不到关于这一点的任何信息,只是在目录中传递对文件进行迭代的引用,这不是我所看到的。此外,将其从命令中删除似乎没有效果

COUNT=$(ls -1 ${DIRNAME} | wc -l)
…是一种计算目录中文件的错误方法:
ls-1
告诉
ls
不要将多个文件放在一行上;确保
wc-l
将通过计算行数来计算文件数

现在,让我们谈谈“童车”:

  • 文件名可以包含文字换行符。
    ls
    的一个版本如何处理这个问题是由实现定义的;有些版本可能会重复计算这些文件(GNU系统不会,但我不想打赌,比如说,
    busybox
    在嵌入式路由器上随机发布)
  • ${DIRNAME}
    的无引号扩展允许在传递到
    ls
    之前对目录名进行字符串拆分和全局扩展,因此如果名称包含空格,则它可以成为多个参数。这应该是
    “$DIRNAME”
    “${DIRNAME}”
…此外,这也是低效的,因为它调用多个外部工具(
ls
wc
)来执行shell可以在内部管理的操作


如果您想要更强大的功能,此版本将适用于所有POSIX shell:

count_entries() { set -- "${1:-.}"/*; if [ -e "$1" ]; then echo "$#"; else echo 0; fi; }
count=$(count_entries "$DIRNAME") ## ideally, DIRNAME should be lower-case.
…或者,如果您想让它更快地执行(不需要子shell),请参阅以下内容(仅针对bash):

…或者,如果您的目标是bash,并且不想麻烦处理函数,则可以使用数组:

files=( "$DIRNAME"/* )
if [[ -e "${files[0]}" || -L "${files[0]}" ]]; then
  echo "At least one file exists in $DIRNAME"
  echo "...in fact, there are exactly ${#files[@]} files in $DIRNAME"
else
  echo "No files exist in $DIRNAME"
fi

最后——如果你想处理一个文件名太大而不能适应内存,并且你有GNU<代码>查找< /C>,请考虑使用:

find "$DIRNAME" -mindepth 1 -maxdepth 1 -printf '\n' | wc -l
…这完全避免了将名称放入流中(从而生成一个流,如果选择的话,可以简单地以字节而不是行数来测量其长度)。

补充:
有一个边缘案例他的答案没有涵盖:如果第一个目录条目恰好是一个断开的符号链接,那么使用
-e
测试glob扩展是不够的,因为Bash总是将存在性测试应用于符号链接的目标,而在断开的符号链接的情况下,根据定义,这是不存在的。换句话说:对于断开的符号链接,
-e
将指示false,即使链接本身存在。因此,一个完全健壮的解决方案必须使用类似于
[-e“$1”| |-L“$1”]]

-L
测试其参数是否为符号链接,无论是否已断开。)

这里有一个稍微短一点的bash(使用子shell):

  • shopt-s nullglob
    确保模式在没有匹配的情况下扩展为空字符串
  • entries=(*)
    收集数组中的所有匹配项(在当前目录中)
  • echo“${#entries[@]}”
    输出元素数组计数
  • 由于不涉及任何外部实用程序,因此此命令不受
    getconf ARG_MAX
    限制,因此应适用于大目录
请注意,上述是否也计算隐藏(
*
)项取决于
dotglob
选项的状态。 但是,很容易将包含或不包含逻辑的固定隐藏项构建到命令中:

明确包含隐藏项:

count=$(shopt -s nullglob dotglob; entries=(*); echo "${#entries[@]}")
count=$(shopt -s nullglob; shopt -u dotglob; entries=(*); echo "${#entries[@]}")
明确排除隐藏项:

count=$(shopt -s nullglob dotglob; entries=(*); echo "${#entries[@]}")
count=$(shopt -s nullglob; shopt -u dotglob; entries=(*); echo "${#entries[@]}")

可以将上述所有内容包装在灵活的功能中

countEntries [<dir>] ... counts based on current state of the `dotglob` option
countEntries <dir> 0 ... counts non-hidden entries only
countEntries <dir> 1 ... counts all entries, including hidden ones
countEntries[]。。。基于“dotglob”选项的当前状态的计数
countEntries 0。。。仅统计非隐藏项
countEntries 1。。。统计所有条目,包括隐藏条目
#/usr/bin/env bash
#概要
#countEntries[[]
#描述
#默认为。
#默认为“shopt dotglob”的当前状态;
#值0显式排除,1显式包括隐藏项。
countEntries()(#在子单元格中运行整个函数。
本地目录=${1:-.}includeHidden=$2个条目
shopt-s nullglob
案例$includeHidden in
0)#排除隐藏条目
shopt-u dotglob
;;
1) #包括隐藏条目
shopt-s dotglob
;;
#否则:使用'dotglob'的*当前状态*`
以撒
条目=(“$1”/*)#在数组中收集
回显“${#条目[@]}”输出计数。
)

为每个文件发出一行输出……是的,当输出不是到终端时,这是默认值,但显式优于隐式。顺便说一句——请参见第四段——保留所有caps环境变量名称;应用程序使用时,应首选带有小写字符的名称。当然,您不一定要导出
ing
COUNT
,但shell变量和环境变量共享一个名称空间(shell变量将自动覆盖/修改任何类似命名的环境变量),因此按照约定,应首选小写名称。顺便说一句,请参阅(你可以点击进入你关心的嵌套级别,包括描述
-1
参数到
ls
)……也是你的朋友(会找到未引用的扩展bug,f'rinstance)。你会解释bug并提出安全的方法吗?谢谢。我观察到如果字符串由
${DIRECTORY}表示
非常长,在极端情况下,您可能会遇到问题,因为名称太长。我注意到,您可以使用
set--
设置比后续外部命令处理更长的参数列表:
set--$(perl-e'for$I(1..1000){printf“%.5d-%s.txt\n,$I,“ABC”x 256;}');echo$#echo“$@”在Mac OS X 10.10 Yosemite上,这产生了
1000
(来自
echo$#
),
1 1000 779000
(来自
e