Вопрос

I have a script:

#!/bin/bash
SINGLE_FILE=/tmp/blah.file
MULTIPLE_FILES=/tmp/{dir1,dir2}/*.file

cp $SINGLE_FILE $MULTIPLE_FILES /tmp/newDir

This will fail with:

cp: cannot stat `/tmp/{dir1,dir2}/*.file': No such file or directory

It looks like the script is not expanding out the wildcards in my variables. So I can make this script work with:

eval cp $SINGLE_FILE $MULTIPLE_FILES /tmp/newDir

My question is: Why is the script not expanding my variable in the first place? Also, is there a different way to solve this other than using eval?

Это было полезно?

Решение

The script is expanding your variable, to the value you set it to, i.e. /tmp/{dir1,dir2}/*.file, right?

And as you have rightly discovered, you then need to ask the shell to 'run thru that line again' and re evaluate any variables you find there.

So, no other way besides eval (well you could subshell stuff and waste a lot of processing power, and essentially remake the feature of eval with your own code.)

The only thing I can recommend is to use the shell debugging feature set -vx to see for yourself how it is working, i.e.

$set -vx
set -vx
>set -vx
$SINGLE_FILE=/tmp/blah.file
SINGLE_FILE=/tmp/blah.file
>SINGLE_FILE=/tmp/blah.file

$MULTIPLE_FILES=/tmp/{dir1,dir2}/*.file
MULTIPLE_FILES=/tmp/{dir1,dir2}/*.file
>MULTIPLE_FILES='/tmp/{dir1,dir2}/*.file'

$echo /tmp/blah.file '/tmp/{dir1,dir2}/*.file' /tmp/newDir
echo /tmp/blah.file '/tmp/{dir1,dir2}/*.file' /tmp/newDir
>echo /tmp/blah.file '/tmp/{dir1,dir2}/*.file' /tmp/newDir
/tmp/blah.file /tmp/{dir1,dir2}/*.file /tmp/newDir

$eval echo /tmp/blah.file '/tmp/{dir1,dir2}/*.file' /tmp/newDir
eval echo /tmp/blah.file '/tmp/{dir1,dir2}/*.file' /tmp/newDir
>eval echo /tmp/blah.file '/tmp/{dir1,dir2}/*.file' /tmp/newDir
echo /tmp/blah.file /tmp/{dir1,dir2}/*.file /tmp/newDir
>echo /tmp/blah.file '/tmp/dir1/*.file' '/tmp/dir2/*.file' /tmp/newDir
/tmp/blah.file /tmp/dir1/*.file /tmp/dir2/*.file /tmp/newDir

Другие советы

It seems that it's the braces that are confusing things here. IMO, that inconsistency is a bug in the shell - if you had MULTIPLE_FILES=/tmp/dir1/*.file, it would expand that immediately. Add the braces, and then it stops trying to expand. Which is different when you're running anything else.

In the meantime, eval isn't a bad solution/workaround here. The only other one I can think of off the top of my head would be MULTIPLE_FILES=$(echo /tmp/{dir1,dir2}/*.file), which isn't necessarily any better.

In general, I try to avoid this type of thing, as proper shell parsing is hard when spaces are in file/directory names. Instead, I try to use find ... -print0 | xargs -0 ... as much as possible. Or straight into another scripting language like perl.

You could use an array:

SINGLE_FILE=/tmp/blah.file
MULTIPLE_FILES=( /tmp/{dir1,dir2}/*.file )
cp -t /tmp/newDir "$SINGLE_FILE" "${MULTIPLE_FILES[@]}"
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top