"ls -1 path"中的-1是什么意思?
What does -1 in "ls -1 path" mean?
我正在查看一些 shell 代码,这些代码旨在获取目录中文件的数量。上面写着:
COUNT=$(ls -1 ${DIRNAME} | wc -l)
-1
部分是什么意思?我在任何其他问题中找不到任何关于此的信息,只是传递对迭代目录中文件的引用,这不是我正在查看的目录。另外,从命令中删除它似乎没有效果。
COUNT=$(ls -1 ${DIRNAME} | wc -l)
...是计算目录中文件数量的错误方法:ls -1
告诉 ls
不要将多个文件放在一行;确保 wc -l
然后会通过计算行数来计算文件数。
现在,让我们谈谈 "buggy":
- 文件名可以包含文字换行符。
ls
的一个版本如何处理这个是实现定义的;某些版本可能会重复计算此类文件(GNU 系统不会,但我不想打赌 busybox
在嵌入式路由器上浮动的随机版本)。
-
${DIRNAME}
的不加引号扩展允许目录名称在传递给 ls
之前进行字符串拆分和全局扩展,因此如果名称包含空格,它可以成为多个参数。这应该是 "$DIRNAME"
或 "${DIRNAME}"
。
...此外,这是低效的,因为它调用多个外部工具(ls
和 wc
)来做一些 shell 可以在内部管理的事情。
如果您想要更强大的功能,此版本将适用于所有 POSIX shells:
count_entries() { set -- "${1:-.}"/*; if [ -e "" ]; then echo "$#"; else echo 0; fi; }
count=$(count_entries "$DIRNAME") ## ideally, DIRNAME should be lower-case.
...或者,如果您希望它执行得更快(不需要 subshell),请参阅以下内容(仅针对 bash):
# like above, but write to a named variable, not stdout
count_entries_to_var() {
local destvar=
set -- "${2:-.}"/*
if [[ -e "" || -L "" ]]; then
printf -v "$destvar" %d "$#"
else
printf -v "$destvar" %d 0
fi
}
count_entries_to_var count "$DIRNAME"
...或者,如果您的目标是 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 find
,请考虑使用它:
find "$DIRNAME" -mindepth 1 -maxdepth 1 -printf '\n' | wc -l
...这完全避免了将名称放入流中(因此生成一个流,如果选择的话,可以简单地以字节为单位测量长度而不是行数)。
补充:
有一个边缘情况他的回答没有涵盖:如果第一个目录条目恰好是一个 broken symlink,测试使用 -e
的 glob 扩展是不够的,因为 Bash 总是将存在性测试应用于 symlink 的 target - 在这种情况下损坏的 symlink 根据定义不存在。换句话说:对于损坏的 symlink,-e
将指示 false,即使 link 本身 存在。因此,一个完全健壮的解决方案必须使用类似 [[ -e "" || -L "" ]]
的东西
(-L
测试它的参数是否是符号 link,是否损坏。)
这里有一个稍微 更短的 bash
替代方案(使用子 shell):
count=$(shopt -s nullglob; entries=(*); echo "${#entries[@]}")
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[@]}")
可以将以上所有内容包装在一个灵活的函数中:
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
#!/usr/bin/env bash
# SYNOPSIS
# countEntries [<dir> [<includeHidden>]]
# DESCRIPTION
# <dir> defaults to .
# <includeHidden> default to the current state of `shopt dotglob`;
# a value of 0 explicitly EXcludes, 1 explicity INcludes hidden items.
countEntries() ( # Run entire function in subhell.
local dir=${1:-.} includeHidden= entries
shopt -s nullglob
case $includeHidden in
0) # EXclude hidden entries
shopt -u dotglob
;;
1) # INclude hidden entries
shopt -s dotglob
;;
# Otherwise: use *current state* of `dotglob`
esac
entries=(""/*) # Collect in array
echo "${#entries[@]}" # Output count.
)
我正在查看一些 shell 代码,这些代码旨在获取目录中文件的数量。上面写着:
COUNT=$(ls -1 ${DIRNAME} | wc -l)
-1
部分是什么意思?我在任何其他问题中找不到任何关于此的信息,只是传递对迭代目录中文件的引用,这不是我正在查看的目录。另外,从命令中删除它似乎没有效果。
COUNT=$(ls -1 ${DIRNAME} | wc -l)
...是计算目录中文件数量的错误方法:ls -1
告诉 ls
不要将多个文件放在一行;确保 wc -l
然后会通过计算行数来计算文件数。
现在,让我们谈谈 "buggy":
- 文件名可以包含文字换行符。
ls
的一个版本如何处理这个是实现定义的;某些版本可能会重复计算此类文件(GNU 系统不会,但我不想打赌busybox
在嵌入式路由器上浮动的随机版本)。 -
${DIRNAME}
的不加引号扩展允许目录名称在传递给ls
之前进行字符串拆分和全局扩展,因此如果名称包含空格,它可以成为多个参数。这应该是"$DIRNAME"
或"${DIRNAME}"
。
...此外,这是低效的,因为它调用多个外部工具(ls
和 wc
)来做一些 shell 可以在内部管理的事情。
如果您想要更强大的功能,此版本将适用于所有 POSIX shells:
count_entries() { set -- "${1:-.}"/*; if [ -e "" ]; then echo "$#"; else echo 0; fi; }
count=$(count_entries "$DIRNAME") ## ideally, DIRNAME should be lower-case.
...或者,如果您希望它执行得更快(不需要 subshell),请参阅以下内容(仅针对 bash):
# like above, but write to a named variable, not stdout
count_entries_to_var() {
local destvar=
set -- "${2:-.}"/*
if [[ -e "" || -L "" ]]; then
printf -v "$destvar" %d "$#"
else
printf -v "$destvar" %d 0
fi
}
count_entries_to_var count "$DIRNAME"
...或者,如果您的目标是 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 find
,请考虑使用它:
find "$DIRNAME" -mindepth 1 -maxdepth 1 -printf '\n' | wc -l
...这完全避免了将名称放入流中(因此生成一个流,如果选择的话,可以简单地以字节为单位测量长度而不是行数)。
补充
有一个边缘情况他的回答没有涵盖:如果第一个目录条目恰好是一个 broken symlink,测试使用 -e
的 glob 扩展是不够的,因为 Bash 总是将存在性测试应用于 symlink 的 target - 在这种情况下损坏的 symlink 根据定义不存在。换句话说:对于损坏的 symlink,-e
将指示 false,即使 link 本身 存在。因此,一个完全健壮的解决方案必须使用类似 [[ -e "" || -L "" ]]
的东西
(-L
测试它的参数是否是符号 link,是否损坏。)
这里有一个稍微 更短的 bash
替代方案(使用子 shell):
count=$(shopt -s nullglob; entries=(*); echo "${#entries[@]}")
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[@]}")
可以将以上所有内容包装在一个灵活的函数中:
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
#!/usr/bin/env bash
# SYNOPSIS
# countEntries [<dir> [<includeHidden>]]
# DESCRIPTION
# <dir> defaults to .
# <includeHidden> default to the current state of `shopt dotglob`;
# a value of 0 explicitly EXcludes, 1 explicity INcludes hidden items.
countEntries() ( # Run entire function in subhell.
local dir=${1:-.} includeHidden= entries
shopt -s nullglob
case $includeHidden in
0) # EXclude hidden entries
shopt -u dotglob
;;
1) # INclude hidden entries
shopt -s dotglob
;;
# Otherwise: use *current state* of `dotglob`
esac
entries=(""/*) # Collect in array
echo "${#entries[@]}" # Output count.
)