mv foo* ~/bar/如果没有匹配的文件,则类似命令会在 stderr 中生成此消息foo*。
mv: cannot stat `foo*': No such file or directory
Run Code Online (Sandbox Code Playgroud)
但是,在我正在处理的脚本中,这种情况完全没有问题,我想从我们的日志中省略该消息。
有没有什么好的方法可以让你mv保持安静,即使什么都没有移动?
小智 64
你在找这个吗?
$ mv file dir/
mv: cannot stat ‘file’: No such file or directory
$ mv file dir/ 2>/dev/null
# <---- Silent ----->
Run Code Online (Sandbox Code Playgroud)
Mir*_*kár 17
实际上,我不认为静音mv是一种好方法(请记住,它可能还会报告您可能感兴趣的其他事情……例如丢失~/bar)。您只想在 glob 表达式不返回结果的情况下将其静音。事实上,根本不执行它。
[ -n "$(shopt -s nullglob; echo foo*)" ] && mv foo* ~/bar/
Run Code Online (Sandbox Code Playgroud)
看起来不是很吸引人,只能在bash.
或者
[ 'foo*' = "$(echo foo*)" ] || mv foo* ~/bar/
Run Code Online (Sandbox Code Playgroud)
只有除非你是在bash用nullglob一套。不过,您要付出 3 倍重复 glob 模式的代价。
poi*_*ige 13
find . -maxdepth 1 -name 'foo*' -type f -print0 | xargs -0r mv -t ~/bar/
— GNUmv有很好的“目标优先”选项 ( -t),xargs如果根本没有输入,可以跳过运行它的命令 ( -r)。使用-print0和-0相应地确保当文件名包含空格和其他“有趣”的东西时不会出现混乱。
重要的是要意识到实际上是 shell 将其扩展foo*为匹配的文件名列表,因此它自己几乎mv无能为力。
这里的问题是,当 glob 不匹配时,一些 shell bash(以及大多数其他类似 Bourne 的 shell,这种错误行为实际上是由 Bourne shell 在 70 年代后期引入的)会将模式逐字传递给命令。
所以在这里,当foo*不匹配任何文件时,而不是中止命令(如前 Bourne shell 和几个现代 shell 所做的那样),shell 将逐字foo*文件传递给mv,因此基本上要求mv移动名为foo*.
那个文件不存在。如果是这样,它实际上会与模式匹配,因此会mv报告错误。如果该模式被foo[xy]替换,则mv可能会意外移动一个名为foo[xy]而不是fooxandfooy文件的文件。
现在,即使在那些没有这个问题的 shell 中(pre-Bourne、csh、tcsh、fish、zsh、bash -O failglob),你仍然会在 上得到一个错误mv foo* ~/bar,但这次是由 shell。
如果您想在没有文件匹配的foo*情况下将其视为错误并且在这种情况下不移动任何内容,则您需要首先构建文件列表(以不会导致错误的方式,例如使用nullglob选项一些shell),然后唯一调用的mv是列表非空。
这比隐藏(添加会)的所有错误更好,好像由于任何其他原因而失败,您可能仍然想知道原因。mv2> /dev/nullmv
files=(foo*(N)) # where the N glob qualifier activates nullglob for that glob
(($#files == 0)) || mv -- $files ~/bar/
Run Code Online (Sandbox Code Playgroud)
或者使用匿名函数来避免使用临时变量:
() { (($# == 0)) || mv -- "$@" ~/bar/; } foo*(N)
Run Code Online (Sandbox Code Playgroud)
zsh是那些没有 Bourne 错误的 shell 之一,并且在 glob 不匹配(并且该nullglob选项尚未启用)时报告错误而不执行命令,因此在这里,您可以隐藏zsh错误并恢复stderr formv因此您仍然会看到mv错误(如果有),但不会看到有关不匹配的 glob 的错误:
(mv 2>&3 foo* ~/bar/) 3>&2 2>&-
Run Code Online (Sandbox Code Playgroud)
或者zargs,如果foo*glob 扩展为 man 文件,您也可以使用which 也可以避免问题。
autoload zargs # best in ~/.zshrc
zargs -r -- foo* -- mv -t ~/bar # here assuming GNU mv for its -t option
Run Code Online (Sandbox Code Playgroud)
files=(~(N)foo*)
((${#files[#]} == 0)) || mv -- "${files[@]}" ~/bar/
Run Code Online (Sandbox Code Playgroud)
bash没有语法可以nullglob只为一个 glob启用,并且该failglob选项会取消,nullglob因此您需要以下内容:
saved=$(shopt -p nullglob failglob) || true
shopt -s nullglob
shopt -u failglob
files=(foo*)
((${#files[@]} == 0)) || mv -- "${files[@]}" ~/bar/
eval "$saved"
Run Code Online (Sandbox Code Playgroud)
或在子shell中设置选项以保存必须在之前保存它们并在之后恢复它们。
(
shopt -s nullglob
shopt -u failglob
files=(foo*)
((${#files[@]} == 0)) || mv -- "${files[@]}" ~/bar/
)
Run Code Online (Sandbox Code Playgroud)
yash(
set -o nullglob
files=(foo*)
[ "${#files[@]}" -eq 0 ] || mv -- "${files[@]}" ~/bar/
)
Run Code Online (Sandbox Code Playgroud)
fish在 fish shell 中, nullglob 行为是set命令的默认行为,因此它只是:
set files foo*
count $files > /dev/null; and mv -- $files ~/bar/
Run Code Online (Sandbox Code Playgroud)
nullglobPOSIX 中没有选项,sh除了位置参数之外没有数组。您可以使用一个技巧来检测 glob 是否匹配:
set -- foo[*] foo*
if [ "$1$2" != 'foo[*]foo*' ]; then
shift
mv -- "$@" ~/bar/
fi
Run Code Online (Sandbox Code Playgroud)
通过同时使用 afoo[*]和foo*glob,我们可以区分没有匹配文件的情况和有一个文件恰好被调用的情况foo*(aset -- foo*不能这样做)。