Replacing 'source file' with its content, and expanding variables, in bash

In a script.sh,

source a.sh
source b.sh

CMD1
CMD2
CMD3

how can I replace the source *.sh with their content (without executing the commands)? I would like to see what the bash interpreter executes after sourcing the files and expanding all variables.

I know I can use set -n -v or run bash -n -v script.sh 2>output.sh, but that would not replace the source commands (and even less if a.sh or b.sh contain variables).

I thought of using a subshell, but that still doesn't expand the source lines. I tried a combination of set +n +v and set -n -v before and after the source lines, but that still does not work.

I'm going to send that output to a remote machine using ssh. I could use <<output.sh to pipe the content into the ssh command, but I can't log as root onto the remote machine, but I am however a sudoer. Therefore, I thought I could create the script and send it as a base64-encoded string (using that clever trick ) base64 script | ssh remotehost 'base64 -d | sudo bash'

Is there a solution? Or do you have a better idea?

Upvotes: 6

Views: 1909

Answers (1)

dimid
dimid

Reputation: 7631

You can do something like this:

inline.sh:

#!/usr/bin/env bash
while read line; do
    if [[ "$line" =~ (\.|source)\s+.+ ]]; then
        file="$(echo $line | cut -d' ' -f2)"
        echo "$(cat $file)"
    else
      echo "$line"
    fi
done < "$1"

Note this assumes the sourced files exist, and doesn't handle errors. You should also handle possible hashbangs. If the sourced files contain themselves source, you need to apply the script recursively, e.g. something like (not tested):

while egrep -q '^(source|\.)' main.sh; do
    bash inline.sh main.sh > main.sh
done

Let's test it

main.sh:

source a.sh
. b.sh

echo cc
echo "$var_a $var_b"

a.sh:

echo aa
var_a="stack" 

b.sh:

echo bb
var_b="overflow"

Result:

bash inline.sh main.sh

echo aa
var_a="stack"
echo bb
var_b="overflow"

echo cc
echo "$var_a $var_b"

bash inline.sh main.sh | bash

aa
bb
cc
stack overflow

BTW, if you just want to see what bash executes, you can run

bash -x [script]

or remotely

ssh user@host -t "bash -x [script]"

Upvotes: 6

Related Questions