2

I would like to execute commands inside a shell script and store in a variable, but it is opening a new shell which I do not want. Is there any way to correct this? Here is my script.

#!/bin/bash
V1=`<any_command>`      #The shell should not open a new shell
V2=`<another_command>`  #The shell should not open a new shell

I can execute the shell script like below to execute on same shell:

. ./Script.sh

But if there are commands inside shell script to be stored in variable and for that I use

V1=`<any_command>` 

Which still opens a new shell, which I do not want.

  • 4
    Can we see an example of <any_command>? It seems like your problem lies in that you're executing inside your ticks. – Zachary Brady Nov 23 '16 at 14:23
  • The commands are database sql commands, which retrieve data from temporary tables (temp tables are session dependent) . if it will be executed in new sub shell, it will fail as it can not retrieve data from temp tables. Hence, i do not want to open a new shell . – Debasish Nov 24 '16 at 09:33

1 Answers1

4

If you store the output of a command in a variable, that command is executed in a subshell. There's no escaping this. If you want to both retain changes in the shell context (variables, redirections, etc.) and capture the output, you'll need to organize your script differently.

One way is to use a temporary file. This is portable (works in any POSIX sh, except that the way to create a temporary file isn't POSIX) and non-invasive (you can treat any_command as a black box, you don't have to modify it).

unset tmp1
trap 'rm -f "$tmp1"' EXIT INT TERM HUP
tmp1="$(mktemp)"
any_command >"$tmp1"
V1=$(cat "$tmp1")
rm "$tmp1"

A portable, but invasive, way to avoid using a temporary file is to change any_command so that it collects its output in a variable. This requires making each external command call append to that variable. This is particularly cumbersome if there are function calls, since the code of the function needs to be changed. Example:

f () {
  echo "$1"
  a=$((a+$1))
  echo "$2"
}
V1=$(f 4 2)

is to be changed to

f_into_V1 () {
  V1="${V1}${1}"
  a=$((a+$1))
  V1="${V1}${2}"
}
f_into_V1 4 2
  • Thanks Gilles. What i am doing here is executing some Database sql commands and storing the result in a variables to apply some more logic on it. But all the SQLs are fetching data from temporary tabales. Temp tables are session specific, so i do not want to open a new shell because new shell will not able to fetch data from the same temp tables. it is possible only from the same session and same shell. – Debasish Nov 24 '16 at 09:39
  • Thanks Gilles, it worked as you you advised by storing the results in temp file. – Debasish Nov 24 '16 at 10:00
  • @Debasish So if i understand correctly, you want to open a connection to a database and make several successive queries that depend on the results of previous ones? Then reworking the logic of your script is the best solution. In ksh/bash/zsh you could put the database calls in a coprocess, and in the main process you can use echo, read and the like to communicate with the coprocess (e.g. read -r line <${COPROC[0]} in bash). But this would be easier in Perl/Python/Ruby. – Gilles 'SO- stop being evil' Nov 24 '16 at 10:57