I have a shell function (in .bashrc) which creates a temp file, executes the arguments (including all sequence of pipelines), redirects it to a temp file and then open it in VS Code.

I invoke the shell function as

Temp "ls | nl"

In the follwoing code, I tried to make it work. I break the entire string with IFS as a space, store it in an array. Now I want to execute the entire sequence of pipelines and redirect the final stdout to the temp file. How can I achieve this.? I know that for loop won't work here. But I want to print the entire array.

Temp() {
    a="$(mktemp --suffix=.md "/tmp/$1-$(GetFilename "$2")-XXX")"
    IFS=' ' read -r -a Array <<< "$1"
    nArray=${#Array[@]} # Size of array
    for ((i=0; i<nArray; i=i+1)); do

    #"${@}" > "$a"
    code -r "$a"

In the interactive terminal session the following works:

cat <<EOF
$(ls | nl)

So, I tried Heredoc, instead of the for loop inside the function

cat > "$a" <<EOF

But this puts quotes around | and thus fails.

The above would work, if we could remove the quotes somehow.

This also doesn't work

cat > "$a" <<EOF
$(echo $1 | sed "s/'//g")

1 Answer 1


If you want a function to execute a shell command given as an argument, you'll need to use eval on the string, e.g. this prints FOO:

eval_arg() {
    eval "$1"
eval_arg "echo foo |tr a-z A-Z"

Just expanding "$1" won't do, since shell grammar like pipes, quotes and redirections aren't processed after parameter expansions. Splitting the first argument to an array or to $@ doesn't really change this.

So, $(ls | nl) has a verbatim pipe character, which is processed in the shell, but in $($1), any special characters within the value of $1 aren't processed (apart from word splitting and globs). There are no quotes in play here.

As for that last example, $(echo $1 | sed "s/'//g") splits the value of $1 on whitespace (word splitting with the default IFS), then joins the words with spaces (echo), passes that as input to sed which removes any single quotes there.


$ set -- "'foo  bar'"
$ $(echo $1 | sed "s/'//g")
foo bar 

The outer quotes in the set command are processed by the shell, while the inner quotes are part of the value. Note that just set -- 'foo bar' would not result in $1 containing any quotes, the only quotes here would be removed as part of the normal shell processing.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .