function mv1 { mv -n "$1" "targetdir" -v |wc -l ;}
mv1 *.png
它只会移动.png
找到的第一个文件,而不是所有文件。
如何使该命令应用于与通配符匹配的所有文件?
答案1
mv1 *.png
首先将通配符模式扩展*.png
为匹配文件名列表,然后将该文件名列表传递给函数。
然后,在函数内部$1
意味着:将第一个参数传递给函数,在包含空格的地方将其拆分,并替换任何包含通配符的空格分隔部分,并通过匹配文件名列表匹配至少一个文件名。听起来很复杂?确实如此,而且这种行为只是偶尔有用,而且经常会出现问题。这种拆分和匹配行为仅发生$1
在双引号之外,因此修复很简单:使用双引号。始终在变量替换两边加上双引号除非你有充分的理由不这样做。
例如,如果当前目录包含两个文件A* algorithm.png
和graph1.png
,则作为第一个参数mv1 *.png
传递A* algorithm.png
给函数,并graph1.png
作为第二个参数传递。然后$1
分为A*
和algorithm.png
。该模式A*
匹配A* algorithm.png
, 并且algorithm.png
不包含通配符。因此该函数最终mv
以参数-n
、A* algorithm.png
、algorithm.png
和运行targetdir
。-v
如果您将函数更正为
function mv1 { mv -n "$1" "targetdir" -v |wc -l ;}
那么它将正确移动第一个文件。
处理全部参数,告诉 shell 处理所有参数而不仅仅是第一个参数。您可以使用"$@"
来表示传递给函数的参数的完整列表。
function mv1 { mv -n "$@" "targetdir" -v |wc -l ;}
这几乎是正确的,但如果文件名恰好以字符 开头-
,它仍然会失败,因为mv
会将该参数视为选项。传递--
tomv
告诉它“此后没有更多选项”。这是大多数命令都支持的非常常见的约定。
function mv1 { mv -n -v -- "$@" "targetdir" |wc -l ;}
剩下的问题是,如果mv
失败,该函数将返回成功状态,因为管道左侧命令的退出状态被忽略。在 bash(或 ksh)中,您可以使用set -o pipefail
使管道失败。请注意,设置此选项可能会导致同一 shell 中运行的其他代码失败,因此您应该在函数中本地设置它,这从 bash 4.4 开始是可能的。
function mv1 {
local -
set -o pipefail
mv -n -v -- "$@" "targetdir" | wc -l
}
在早期版本中,设置pipefail
会很脆弱,因此最好PIPESTATUS
明确检查。
function mv1 {
mv -n -v -- "$@" "targetdir" | wc -l
((!${PIPESTATUS[0] && !${PIPESTATUS[1]}}))
}
答案2
$1
是函数的第一个参数,这里是第一个匹配的文件*.png
。我想这"$@"
就是您想要使用的而不是$1
.
答案3
你必须使用mv1 \*.png
.
与函数交互时,Linux 终端不会直接将星号传递给命令,而是选择第一个匹配的参数并将其传递给命令。
为了让星号直接通过,需要使用反斜杠转义星号。