Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why the Linux command CP behave differently in CLI and in script?

Tags:

linux

bash

cp

I want to copy a bunch of Verilog/systemverilog sources, so I use CP with wildcard expression:

cp <some_dir>/*.{v,sv,svh} .

It works. But when I put it to a script with exactly the same line, the CP command fails with the log:

cp: cannot stat `../../mytest/spiTest/*.{v,sv,svh}': No such file or directory

How is that happening?

PS: I use bash as the shell.


And here is my script:

#!/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 .

I do changed the first line to

#!/bin/bash -vx

and run this script again, and I get:

#!/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
like image 827
Mr.Zhou Avatar asked Dec 24 '22 20:12

Mr.Zhou


1 Answers

Check the first line of the script. It probably reads:

#!/bin/sh

which switches the shell from BASH to Bourne Shell. Use

#!/bin/bash

instead.

[EDIT] You're running into problems with expansion. BASH has a certain order in which it expands patterns and variables. That means:

f5="$rdir/*.{v,sv,svh}" #testbench files

is quoted, so no file name expansion happens at this time. Only the variable $rdir is expanded. When

cp $f5 .

is executed, BASH first looks for file names to expand and there are none. Then it expands variables (f5) and then calls cp with two arguments: ../../mytest/spiTest/*.{v,sv,svh} and .. Since cp expects the shell to have performed the file name expansion already, you get an error.

To fix this, you have to use arrays:

f5=($rdir/*.{v,sv,svh})

This replaces the variable and then expands the file names and puts everything into the array f5. You can then call cp with this array while preserving whitespaces:

cp "${f5[@]}" .

Every single character here is important. [@] tells BASH to expand the whole array here. The quotes say: Preserve whitespace. {} is necessary to tell BASH that [@] is part of the variable "name" to expand.

like image 200
Aaron Digulla Avatar answered Mar 22 '23 09:03

Aaron Digulla