如何在使用 'ls' 命令并将输出分配给变量时抑制 stderr?
How to suppress stderr while using 'ls' command along with assigning the output to a variable?
我正在尝试创建一个脚本,该脚本将根据文件名和时间戳在服务器上搜索文件,并将这些文件计数到一个变量中。当文件可用时它工作正常,但当文件不可用时抛出一个 stderr。
为了抑制 stderr,我试图将它重定向到 /dev/null,但即便如此也无济于事,错误仍然显示在屏幕上。我知道我可以先使用 'if' 语句检查文件是否可用,然后进行计数,但这会不必要地使脚本冗长。
那么有没有一种方法可以获取文件计数并抑制 stderr(如果有)以及仅在一行代码中将输出分配给变量?
当服务器上存在名为 'example' 的文件时,此命令成功运行:
file_name=example
file_date=20190901
file_count=`ls -lrt "$PWD"/"$file_name"*"$file_date"* | wc -l`
但是当文件不存在时,它会在屏幕上抛出一个标准错误,如下所示:
ls: cannot access /home/saurap01/example*20190901*: No such file or directory
为了抑制此错误,我尝试将其重定向到 /dev/null,如下所示:
file_count=`ls -lrt "$PWD"/"$file_name"*"$file_date"* | wc -l` > /dev/null 2>&1
但即使这样也无助于抑制错误。
我可以尝试使用以下方法隐藏 stderr:
file_count=`ls -lrt "$PWD"/"$file_name"*"$file_date"* | wc -l` 2>&-
你没有正确重定向 stderr,2>/dev/null
应该紧跟在你想要抑制其 stderr 的命令之后,例如:
file_count=`ls -lrt "$PWD"/"$file_name"*"$file_date"* 2>/dev/null | wc -l`
但是, parsing the output of ls
is not a good idea at all,你应该使用 find
来完成这样的任务。例如,使用 GNU 查找:
find -maxdepth 1 \
-type f \
-name "$file_name*$file_date*" \
-printf '.' | wc -c
或使用任何符合 POSIX 的查找:
find . \
! \( -type d -path '*/*' -prune \) \
-type f \
-name "$file_name*$file_date*" \
-exec printf '.%.s' {} + | wc -c
直接的解决办法是添加
2>/dev/null
里面命令替换。
您的代码表现出许多反模式,所以我们也来讨论一下。
如 useless use of ls
中所述,shell 在将参数传递给 ls
之前已经执行了通配符扩展。此外,您传递给 ls
的选项会执行大量的额外工作;您忽略了大小、所有者等,但您使用 -l
选项查找它们;而且您不关心排序顺序,但是您使用 -rt
.
强制按时间戳排序
此外,如 http://mywiki.wooledge.org/ParsingLs 中所述,命令 ls
具有许多人类可读输出的功能,因此不适合在脚本中使用。
开箱即用的 shell 通常配置为 return glob 模式本身,如果它不匹配任何文件。在 Bash(但不是 ksh
)中,您可以使用
避免这种情况
setopt -s nullglob
然后简单地打印文件;
### BUG; see below
printf '%s\n' ./"$file_name"*"$file_date"* |
wc -l
但是,如果其中一个文件名包含换行符,这将产生错误的结果 - 那么,输出的行数将与文件数不同。一个简单的解决方法是避免使用 printf
并完全使用 shell 的功能。
set -- ./"$file_name"*"$file_date"*
Thrs 将简单地将通配符匹配分配给参数列表 </code>、<code>
等,因此
echo $#
将打印文件数。
如果您没有 Bash(因此没有 shopt
),您可以通过检查第一个文件是否存在来查找 glob 是否扩展到自身。
set -- ./"$file_name"*"$file_date"*
if [ -e "" ]; then
echo "$#"
else
echo 0
fi
作为未成年人,还要注意 "$PWD"
拼写很少有用。如果您需要将相对文件名转换为绝对文件名,或者出于其他原因需要知道当前目录的完整路径,它偶尔会有用;但是在这些场景之外,就是用相对路径来引用当前目录下的东西。
我正在尝试创建一个脚本,该脚本将根据文件名和时间戳在服务器上搜索文件,并将这些文件计数到一个变量中。当文件可用时它工作正常,但当文件不可用时抛出一个 stderr。
为了抑制 stderr,我试图将它重定向到 /dev/null,但即便如此也无济于事,错误仍然显示在屏幕上。我知道我可以先使用 'if' 语句检查文件是否可用,然后进行计数,但这会不必要地使脚本冗长。
那么有没有一种方法可以获取文件计数并抑制 stderr(如果有)以及仅在一行代码中将输出分配给变量?
当服务器上存在名为 'example' 的文件时,此命令成功运行:
file_name=example
file_date=20190901
file_count=`ls -lrt "$PWD"/"$file_name"*"$file_date"* | wc -l`
但是当文件不存在时,它会在屏幕上抛出一个标准错误,如下所示:
ls: cannot access /home/saurap01/example*20190901*: No such file or directory
为了抑制此错误,我尝试将其重定向到 /dev/null,如下所示:
file_count=`ls -lrt "$PWD"/"$file_name"*"$file_date"* | wc -l` > /dev/null 2>&1
但即使这样也无助于抑制错误。
我可以尝试使用以下方法隐藏 stderr:
file_count=`ls -lrt "$PWD"/"$file_name"*"$file_date"* | wc -l` 2>&-
你没有正确重定向 stderr,2>/dev/null
应该紧跟在你想要抑制其 stderr 的命令之后,例如:
file_count=`ls -lrt "$PWD"/"$file_name"*"$file_date"* 2>/dev/null | wc -l`
但是, parsing the output of ls
is not a good idea at all,你应该使用 find
来完成这样的任务。例如,使用 GNU 查找:
find -maxdepth 1 \
-type f \
-name "$file_name*$file_date*" \
-printf '.' | wc -c
或使用任何符合 POSIX 的查找:
find . \
! \( -type d -path '*/*' -prune \) \
-type f \
-name "$file_name*$file_date*" \
-exec printf '.%.s' {} + | wc -c
直接的解决办法是添加
2>/dev/null
里面命令替换。
您的代码表现出许多反模式,所以我们也来讨论一下。
如 useless use of ls
中所述,shell 在将参数传递给 ls
之前已经执行了通配符扩展。此外,您传递给 ls
的选项会执行大量的额外工作;您忽略了大小、所有者等,但您使用 -l
选项查找它们;而且您不关心排序顺序,但是您使用 -rt
.
此外,如 http://mywiki.wooledge.org/ParsingLs 中所述,命令 ls
具有许多人类可读输出的功能,因此不适合在脚本中使用。
开箱即用的 shell 通常配置为 return glob 模式本身,如果它不匹配任何文件。在 Bash(但不是 ksh
)中,您可以使用
setopt -s nullglob
然后简单地打印文件;
### BUG; see below
printf '%s\n' ./"$file_name"*"$file_date"* |
wc -l
但是,如果其中一个文件名包含换行符,这将产生错误的结果 - 那么,输出的行数将与文件数不同。一个简单的解决方法是避免使用 printf
并完全使用 shell 的功能。
set -- ./"$file_name"*"$file_date"*
Thrs 将简单地将通配符匹配分配给参数列表 </code>、<code>
等,因此
echo $#
将打印文件数。
如果您没有 Bash(因此没有 shopt
),您可以通过检查第一个文件是否存在来查找 glob 是否扩展到自身。
set -- ./"$file_name"*"$file_date"*
if [ -e "" ]; then
echo "$#"
else
echo 0
fi
作为未成年人,还要注意 "$PWD"
拼写很少有用。如果您需要将相对文件名转换为绝对文件名,或者出于其他原因需要知道当前目录的完整路径,它偶尔会有用;但是在这些场景之外,就是用相对路径来引用当前目录下的东西。