使用通配符调用 mv 时出错

使用通配符调用 mv 时出错
#! /bin/bash

error_text=$(tail -n +1 /path/dir/folder/exc/a/update/Abd/ER/* | \
    grep 'Warning\|Loaded\|Event')
echo $error_text

nc 10.10.99.45 25 << EOF
ehlo mail.abc.pvt
mail from: [email protected]
rcpt to: [email protected]
data
subject: errors
$error_text
.
quit
EOF
mv Abc*.err /path/dir/folder/exc/a/update/Abd/ER/BkError/

我得到的错误是

mv: cannot stat `ACQ*.err': No such file or directory

答案1

当使用通配符调用程序时,您使用的 shell 将尝试扩展此通配符并将扩展的文件名作为可执行文件的参数。如果无法扩展,shell 会将通配符作为文件名提供给进程。

查看以下strace输出(文件存在):

user@host:~$ mv test* /tmp/
execve("/bin/mv", ["mv", "test", "test1", "test2", "test3", "/tmp"], [/* 19 vars */]) = 0

现在,此strace输出(不存在与通配符匹配的文件)。

user@host:~$ mv test* /tmp/
execve("/bin/mv", ["mv", "test*", "/tmp/"], [/* 19 vars */]) = 0

当使用 移动文件时mv,程序mv首先尝试获取文件的状态。这是通过系统调用完成的stat(请参阅 参考资料man 2 stat)。如果无法收集文件(或您的情况下的多个文件)的状态,则该mv过程无法继续。

在第二种情况下,stat 系统调用失败:

lstat("test*", 0x7fff20d26490)          = -1 ENOENT (No such file or directory)

长话短说: 不存在与该语句匹配的文件ACQ*.err

答案2

当通配符模式与任何文件都不匹配时,shell 会保持其不变。

为了避免虚假错误,首先让匹配项展开,然后检查结果是否是不存在的文件。 ¹ 您可以将位置参数(通常包含传递给脚本的参数)设置为文件列表。 ²

set -- Abc*.err
if [ -e "$1" ]; then
  mv "$@" /path/dir/folder/exc/a/update/Abd/ER/BkError/
fi

在 bash 中(但不是 plain )sh,您可以更改配置以将不匹配的模式扩展为空字符串,而不是保持它们不变。

shopt -s nullglob
err_files=(Abc*.err)
if ((${#err_files[@]} != 0)); then
  mv "${err_files[@]}" /path/dir/folder/exc/a/update/Abd/ER/BkError/
fi

1这可能会导致包含[…].为了完整起见,您还应该测试扩展是否等于原始值。
²请参阅“如何处理文件名列表”为什么我的 shell 脚本会因为空格或其他特殊字符而卡住?以获得更多解释。

相关内容