我想将所有内容存储command args
在一个中array
,但它只有当所有参数都没有任何(*
)时才有效。
这是一个不使用数组的测试:
mkdir -p /tmp/hello
echo "hello" > /tmp/hello/hello.txt
echo "world" > /tmp/hello/world.txt
mkdir -p /tmp/world
# This cp command is success
cp /tmp/hello/* /tmp/world
现在将 cp 命令转换为 my_array:
mkdir -p /tmp/hello
echo "hello" > /tmp/hello/hello.txt
echo "world" > /tmp/hello/world.txt
mkdir -p /tmp/world
declare -a my_array=()
my_array[0]="cp"
my_array[1]="/tmp/hello/*"
my_array[2]="/tmp/world"
# Run the command and it will fail
"${my_array[@]}"
错误如下:
cp: cannot stat '/tmp/hello/*': No such file or directory
*
在 中可以使用 ( ) 吗?使用 实现 ' ' 的my_array
正确语法是什么?cp /tmp/hello/* /tmp/world
my_array
更新:
有一个problem
来自@choroba's answoer
,$count
和$sedond_item
将是错误的:
mkdir -p /tmp/hello
echo "hello" > /tmp/hello/hello.txt
echo "world" > /tmp/hello/world.txt
mkdir -p /tmp/world
my_array=(cp)
my_array+=(/tmp/hello/*)
my_array+=(/tmp/world)
count=${#my_array[@]}
printf "%s\n" "count is: $count"
sedond_item="${my_array[1]}"
printf "%s\n" "second item is: $sedond_item"
以下是@choroba 回答的输出:
count is: 4
second item is: /tmp/hello/hello.txt
但在我的原始数组中$count
和是正确的:$sedond_item
mkdir -p /tmp/hello
echo "hello" > /tmp/hello/hello.txt
echo "world" > /tmp/hello/world.txt
mkdir -p /tmp/world
declare -a my_array=()
my_array[0]="cp"
my_array[1]="/tmp/hello/*"
my_array[2]="/tmp/world"
count=${#my_array[@]}
printf "%s\n" "count is: $count"
sedond_item="${my_array[1]}"
printf "%s\n" "second item is: $sedond_item"
这是原始数组的输出:
count is: 3
second item is: /tmp/hello/*
我认为你不能安全地在bash 中做你想做的事。
在 bash(以及 POSIX sh 和 ksh)中,参数扩展(包括数组扩展,如
"{my_array[@]}"
支持它们的 shell 中的数组扩展)的双引号可防止单词拆分和文件名生成(也称为 globbing)。另一方面,未加引号的扩展既要进行单词拆分,又要进行 globbing(所谓的“split+glob”操作)。在 bash 中,您可以使用set -f
(或等效地)关闭 globbing,set -o noglob
但据我所知,您不能在保持 globbing开启的情况下关闭单词拆分。请注意,单词拆分发生在通配符之前
/path/without/whitespace/*
,因此问题不在于的扩展/path/without/whitespace/name with whitespace
,而在于 的扩展/path with whitespace/*
。然而,在 zsh 中,未加引号的变量扩展默认不受 split+glob 约束,您可以使用
~
参数扩展标志2单独启用 globbing 。请注意,在所有情况下,即使取消引用,
var=*
或之类的赋值语句的 RHS也不会扩展。my_array[1]=/tmp/hello/*
因此以 zsh 为例(注意 zsh 数组从 1 开始索引,而不是像 bash 那样从 0 开始):
"${my_array[@]}"
(与 bash 和 zsh 中引用的相同)但是您可以通过添加另一个文件来验证扩展时是否发生了通配符:
对于您的具体情况,我建议添加一些安全措施 - 特别是使用 GNU mv
-t
明确设置目标目录并-n
防止意外覆盖,以及一个附加参数--
来标记选项的结束(这在 glob 可能扩展为以连字符开头的文件名时变得很重要):尽管老实说,如果你要切换到 zsh,你可能会考虑使用贡献
zmv
模块 - 它采用(引用的)glob 表达式并在内部扩展它们 - 代替普通的mv
。我的意思是不使用
eval
但请注意,在数组的 每个
${~my_array[@]}
元素扩展期间都会启用通配符填充数组时使用星号,但不要一次填充一个元素:
或者使用
+=
运算符扩展数组: