I'm forced to use a script like below:

# test.sh
function my_fun
    echo "Give value for FOO"
    local my_var
    read my_var
    export FOO=$my_var

# Call my_fun function

by sourcing it from my shell.

$ source test.sh
Give value for FOO
$ echo $FOO

I would like to automate the script with expect like shown below:

$ expect test.exp
$ echo $FOO

The amount and names of the environmental variables in test.sh is unknown.


  • Added my_fun functionc all to test.sh.
  • 1
    How will your expect script know when to stop? Do you need to parse the test.sh script with expect?
    – Jeff Schaller
    Jan 24 '19 at 13:15
  • 1
    if the number of variables is unknown, how do you know what answers to put in the expect script? Jan 24 '19 at 13:19
  • The questions are known but the resulting environmental variables are not. This is also how the expect script knows when to stop waiting for more input.
    – Jaakko
    Jan 24 '19 at 13:31
  • 1
    Consider, separately, sending the input to the function (which I didn't see you calling, above): my_fun <<< something$'\n'"something else"
    – Jeff Schaller
    Jan 24 '19 at 13:42
  • Possible, but I'm trying to avoid this because I think expect is more readable.
    – Jaakko
    Jan 24 '19 at 13:48

The fundamental problem is that a child process cannot alter the environment of its parent. This is why you need to source that shell script, so the environment variables will persist in your current shell.

Expect is designed to spawn child processes. Your current shell cannot be affected by the result of expect test.exp.

However, you can spawn a shell, source that shell script, and then keep that shell around by interacting with it: this is off the top of my head and is untested:

#!/usr/bin/expect -f
set timeout -1
spawn $env(SHELL)
set myprompt "some pattern that matches your prompt"
expect -re $myprompt
send "source test.sh\r"
expect {
    "Give value for " {
        # provide the same answer for every question:
        send "some value\r"
    -re $myprompt

Now you are interacting with the shell you spawned. When you exit that shell, the spawned shell dies, then expect script ends, and you are back in your current shell (without the variables you initialized).

  • Good idea, I think I can spawn extra shell and work on there in the expect.
    – Jaakko
    Jan 24 '19 at 13:35
  • @Jaakko Note that this won't set FOO in the original shell, even if my_fun is called somewhere.
    – Kusalananda
    Jan 24 '19 at 16:52

You can create a create a shell script that diffs the environments from before and after running that function:

# run.sh
source ./test.sh
ENV_BEFORE=$(set | grep -v "^_")
ENV_AFTER=$(set | grep -v "^ENV_BEFORE" | grep -v "^_")
# echo the new environment variables
echo "$ENV_AFTER" | grep -v -F -x -f <(echo "$ENV_BEFORE")

Then run that script using expect:

# test.exp
log_user 0
spawn ./run.sh
expect "Give value for "
expect -re  "(.*)\r\n"
send -- "stackexchange\r\n"
expect -re  "(.*)\r\n"
expect -re  "(.*)\r\n"
puts $expect_out(1,string)

The source the output of that:

$ source <(expect test.exp)
$ echo $FOO
spawn /bin/bash -c ". ./source_script.sh && ./exec_script.sh"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.