Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 412
Frédéric Haziza Avatar asked May 30 '16 18:05

Frédéric Haziza


People also ask

How do I change file content in bash?

To replace content in a file, you must search for the particular file string. The 'sed' command is used to replace any string in a file using a bash script. This command can be used in various ways to replace the content of a file in bash. The 'awk' command can also be used to replace the string in a file.

How do you replace a variable in a file in Linux?

The Syntax for Replacing String For replacing a variable value using sed, we first need to understand how sed works and how we can replace a simple string in any file using sed. In this syntax, you just need to provide the string you want to replace at the old string and then the new string in the inverted commas.

What is $_ in bash?

$_ (dollar underscore) is another special bash parameter and used to reference the absolute file name of the shell or bash script which is being executed as specified in the argument list. This bash parameter is also used to hold the name of mail file while checking emails.

Can a bash script modify itself?

One of the requirements I have is that the script must be self contained; no other files are to accompany the script and there are to be no environment variables. This would require the script to be able to edit itself.


1 Answers

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]"
like image 169
dimid Avatar answered Sep 22 '22 05:09

dimid