3

I have a list of 50 Linux servers that I need to SSH into and check that a key-value pair configuration parameter within a .conf file is set. I need to check that the key-value pair exists. If the key-value pair does exist, I need to modify the boolean value to FALSE. If the key-value pair does not exist, I need to create the key-value pair with value set to FALSE.

I have no issues with the SSH part and using a Here Document to execute a list of commands on the remote server. However, this particular solution requires some bash logic on the remote server for checking the key-value pair and doing operations depending on the results. Is there a way to incorporate bash scripting logic within the Here Document? If not, what are alternative approaches to handling this particular situation?

I suppose I could have a bash script on each server that I then call from within the Here Document that executes the logic I need on the remote server, but I was hoping for a solution that did not require additional files and administering said files on 50 servers.

Example code below to show the logic I am looking at implementing with some pseudocode. Thanks in advance for the help and suggestions.

#! /bin/bash

SERVER_LIST=/path/to/servers_list.txt

for server in $(cat ${SERVER_LIST}); do
    ssh ${server} <<CommandList
    # if key-value pair exists in my.conf
        # modify value to FALSE
    # else
        # add key-value pair with value set to FALSE
CommandList
done

Example configuration file

[general]
setting1 = true
setting2 = false
setting3 = true
6
  • What does the configuration file look like?
    – Kusalananda
    Dec 30, 2022 at 6:08
  • @Kusalananda I have updated the question to show an example of how the configuration file will look. I plan on using sed to handle the modification or addition to the configuration file. After giving this some more thought, I may be able to just use two sed commands with II separator so that if the first fails, then the second will run. So something like: sed -i -e '/setting3/ s/true/false' /path/to/my.conf || sed '/general/,/^$/s/^$/setting3 = true\n/g' /path/to/my.conf
    – g9s0x1
    Dec 30, 2022 at 6:36
  • 1
    Indeed, the here document is a shell script and it can be arbitrarily complex.
    – tripleee
    Dec 30, 2022 at 6:43
  • 3
    It's not clear from your question what exactly it should do. If you want to make sure the file is identical to your local copy, overwriting it is the simplest by far.
    – tripleee
    Dec 30, 2022 at 6:44
  • 2
    As triplee says, copying a master file to each server seems most straightforward. If the file's contents are specific to each server, create the file from a template and copy it over. It would be best to use Ansible for things like this, which has built-in templating and general orchestration support. Since the configuration file seems to be in a structured document format (TOML), editing it with sed is inadvisable.
    – Kusalananda
    Dec 30, 2022 at 6:51

2 Answers 2

3

The better solution as said in comments is to use ansible.

One other solution would be to keep your existing heredoc, and to parse properly your TOML file, you could just use awk:

To test setting3 if it's false or if it's true (then, you can apply any logic after in if/then/else/fi):

#! /bin/bash

while read -r server; do
    ssh ${server} <<'CommandList'
    if awk '($1 == "setting3"){exit ($3 == "true") ? 0 : 1}' file.toml; then
        echo "true case"
    else
        echo "false case"
    fi
CommandList
done < /path/to/servers_list.txt

If you prefer a real TOML parser instead of awk:

perl -MTOML::XS -MFile::Slurper -E '
  my $file = shift;
  my $toml = File::Slurper::read_binary($file)
    or die "arg1 need to be TOML file\n";
  my $struct = TOML::XS::from_toml($toml)->to_struct();
  if ($struct->{general}->{setting3}) {
    say "true";
    exit 0;
  }
  else {
    say "false";
    exit 1;
  }
' file.toml

Another TOML parser is the Python implementation of yq (the go version don't parse TOML): python yq


To edit in place, you could use

gawk -i inplace .......
0
-1

Using <<something will interpret some of the content until "something" is seen at the beginning of a line.

You can have for exemple $var be interpreted and replaced by $var value, and also $( some shell script here possibly multiline, or with ; or with pipes, all will be interpreted and the resulting output placed as its place in the heredocument )

For exemple:

cat <<EOF
  Hello, I am process $$ running on $( hostname ), and here is a few informations about it:
$( printf "%s\n" "$PATH" | tr ':' '\n' | while read dir; do
    printf "PATH entry %-40s: is on %s filesystem" "$dir" "$( df "$dir" | tail -n 1  | awk '{print $NF}' )"
   done
)
EOF

# this will output something like :
Hello, I am process 25592 running on myhostname, and here is a few informations about it:
PATH entry /usr/local/bin                          : is on / filesystem
PATH entry /usr/bin                                : is on /usr/bin filesystem
...

The exemple is poor, but just to illustrate that the shell does interpret inside the heredoc.

If you do NOT want interpretation, you can use : <<'something'

cat <<'EOF' # only line different from previous ex.
  Hello, I am process $$ running on $( hostname ), and here is a few informations about it:
$( printf "%s\n" "$PATH" | tr ':' '\n' | while read dir; do
    printf "PATH entry %-40s: is on %s filesystem\n" "$dir" "$( df "$dir" | tail -n 1  | awk '{print $NF}' )"
   done )
# will output:
  Hello, I am process $$ running on $( hostname ), and here is a few informations about it:
$( printf "%s\n" "$PATH" | tr ':' '\n' | while read dir; do
    printf "PATH entry %-40s: is on %s filesystem\n" "$dir" "$( df "$dir" | tail -n 1  | awk '{print $NF}' )"
   done )

And yes, on the cat <<something line we can have other things, such as for exemple coloring some of the content of the outputed heredoc:

cat <<something | grep -E --color=always '^|this_will_be_red|this_too'
blah blih
and this_will_be_red ...
and other things
and this_too will be red
foo bar
something
4
  • This is a demo on heredoc (?). Is this answer the question ? Dec 30, 2022 at 8:35
  • @GillesQuenot : I hope ... I am answering the part "Is there a way to incorporate bash scripting logic within the Here Document?" . I am not good at windows scripting but what he needs to do is trivial once he uses the appropriate $( ... ) at the right places within the heredoc (to create for each machine a custom-script that will then be run on the remote machine via ssh). May need some indirection (protect with backslashes some part so as to have them executed only on the remote machine and not locally) Dec 30, 2022 at 8:43
  • I think OP already heredoc, the question is most on the way to edit TOML reliabily Dec 30, 2022 at 8:46
  • I half-agree that he needs more precise answer, but the title clearly ask "can I use bash-scripting logic within here document" and the question I cited above make me think the part he really needs is how to have scripting logic inside the here-document, which is what my answer explains. Dec 30, 2022 at 8:49

You must log in to answer this question.

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