Combine brace and variable expansion in one line

user1371264

I would like to have a logging function that takes filenames as arguments and replicate the stdout to all of these files. This is what I have come up so far:

function logger() {
    exec > >(tee -ia /var/log/{log1,log2})
}

When I try to replace {log1,log2} with {$*}, I get the arguments separated by space. So, I thought I would do something like this:

function logger() {
    exec > >(IFS=,; tee -ia /var/log{"$*"}
}

This fails to do what I want as brace expansion happens before moving on to the variable substitution. So, I thought I could do this:

function logger() {
    exec > >(IFS=,; eval "tee -ia /var/log/\{$*\}")
}

But this behaves the same, ie logger one two creates one single file named {one,two}.

Why is that? How can I get brace expansion to work so that tee writes to multiple files?

Kusalananda

You can't use variable in a brace expansion in bash. See e.g. How can I use $variable in a shell brace expansion of a sequence?

If you don't want to call your logger function as

logger /var/log/log{1,2}

with the function written as

logger () {
    exec > >( tee -ia "$@" )
}

then what you could do is call it as

logger log{1,2}

or

logger log1 log2

and write the function as

logger () {
    for fname do
        set -- "$@" "/var/log/$fname"
        shift
    done
    exec > >( tee -ia "$@" )
}

or shorter (but more or less unreadable),

logger () {
    set -- "${@/#//var/log/}"
    exec > >( tee -ia "$@" )
}

or, if you wish,

logger () {
    exec > >( tee -ia "${@/#//var/log/}" )
}

This rewrites each element of the list of positional parameters by adding /var/log/ to the beginning of each of them. tee is then invoked with the list of modified arguments.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related