我想复制一堆Verilog/systemverilog源,所以我使用带有通配符表达式的CP:
cp <some_dir>/*.{v,sv,svh} .
它有效。但是,当我把它放在一个具有完全相同行的脚本中时,CP命令失败,并显示日志:
cp: cannot stat `../../mytest/spiTest/*.{v,sv,svh}': No such file or directory
这是怎么发生的?
附言:我用bash作为外壳。
这是我的脚本:
#!/bin/bash
rdir=../../mytest/spiTest
f1="$rdir/bench.lst"
f2="$rdir/cphex" #the script to copy rom data
f3="$rdir/make*" #makefile scripts
f4="$rdir/*.hex" #rom files
f5="$rdir/*.{v,sv,svh}" #testbench files
echo 'Copying files...'
cp $f1 $f2 $f3 $f4 .
cp $f5 .
我确实将第一行更改为
#!/bin/bash -vx
然后再次运行这个脚本,我得到:
#!/bin/bash -vx
rdir=../../mytest/spiTest
+ rdir=../../mytest/spiTest
f1="$rdir/bench.lst"
+ f1=../../mytest/spiTest/bench.lst
f2="$rdir/cphex" #the script to copy rom data
+ f2=../../mytest/spiTest/cphex
f3="$rdir/make*" #makefile scripts
+ f3='../../mytest/spiTest/make*'
f4="$rdir/*.hex" #rom files
+ f4='../../mytest/spiTest/*.hex'
f5="$rdir/*.{v,sv,svh}" #testbench files
+ f5='../../mytest/spiTest/*.{v,sv,svh}'
echo 'Copying files...'
+ echo 'Copying files...'
Copying files...
cp $f1 $f2 $f3 $f4 .
+ cp ../../mytest/spiTest/bench.lst ../../mytest/spiTest/cphex ../../mytest/spiTest/makefile ../../mytest/spiTest/makefile.defines ../../mytest/spiTest/rom.hex ../../mytest/spiTest/rom_if.hex .
cp $f5 .
+ cp '../../mytest/spiTest/*.{v,sv,svh}' .
cp: cannot stat `../../mytest/spiTest/*.{v,sv,svh}': No such file or directory
检查脚本的第一行。上面可能写着:
#!/bin/sh
其将外壳从BASH切换到Bourne外壳。使用
#!/bin/bash
相反。
[EDIT]您在扩展时遇到问题。BASH有一定的扩展模式和变量的顺序。这意味着:
f5="$rdir/*.{v,sv,svh}" #testbench files
被引用,因此此时不会进行文件名扩展。只有变量$rdir
被展开。当
cp $f5 .
执行时,BASH首先查找要展开的文件名,但没有。然后它展开变量(f5
),然后用两个参数调用cp
:../../mytest/spiTest/*.{v,sv,svh}
和.
。由于cp
预计shell已经执行了文件名扩展,因此会出现错误。
要解决这个问题,你必须使用数组:
f5=($rdir/*.{v,sv,svh})
这将替换变量,然后展开文件名,并将所有内容放入数组f5
中。然后,您可以使用此数组调用cp
,同时保留空白:
cp "${f5[@]}" .
这里的每一个字符都很重要。[@]
告诉BASH在这里扩展整个数组。引号上写着:保留空白。{}
需要告诉BASH[@]
是要展开的变量"name"的一部分。
问题是:替换的顺序。Bash在变量展开之前执行大括号展开。在cp $f5 .
行中,bash将执行:
- 大括号扩展:n/a
- 这是关键:变量包含一个大括号表达式,但shell在需要时不会立即看到它
- 波浪形展开:n/a
- 参数扩展:是--
cp ../../mytest/spiTest/*.{v,sv,svh} .
- 命令替换:n/a
- 算术展开:n/a
- 工艺替代:不适用
- 分词:不适用
- 文件名扩展:是的,bash在该目录中查找以字符串
.{v,sv,svh}
结尾的文件。它没有找到,nullglob
没有设置,因此该模式没有从命令中删除 - 引号删除:不适用
现在命令被执行,但失败并出现您看到的错误。
https://www.gnu.org/software/bash/manual/bashref.html#Shell-扩展
解决方案:
- 使用Aaron的数组思想
- (不推荐)强制进行第二轮扩展:
eval cp $f5 .
行
f5="$rdir/*.{v,sv,svh}" #testbench files
可能是错的。首先,避免在行尾注释,它们应该(至少为了可读性)在单独的一行中。然后,避免在变量赋值中使用globbing。因此,删除该行,稍后进行编码(即,用替换旧的cp $f5 .
行)
cp "$rdir"/*.{v,sv,svh} .
顺便说一句,我想测试一下"$rdir"
确实是一个带有的目录
if [ ! -d "$rdir" ] ; then
echo invalid directory $rdir > /dev/stderr
exit 1
fi
您应该阅读高级Bash脚本指南