1

I'm quite new at bash and I am trying to learn it by creating some small scripts.

I created a small script to look up the DNS entry for multiple domains at the same time. The domains are given as attributes.

COUNTER=0
DOMAINS=()

for domain in "$@"
do
    WOUT_WWW=$(dig "$domain" +short)
    if (( $(grep -c . <<<"$WOUT_WWW") > 1 )); then WOUT_WWW="${WOUT_WWW##*$'\n'}" ; fi

    WITH_WWW=$(dig "www.${domain}" +short)
    if (( $(grep -c . <<<"$WITH_WWW") > 1 )); then WITH_WWW="${WITH_WWW##*$'\n'}" ; fi


    DOMAINS[$COUNTER]="$domain|$WOUT_WWW|$WITH_WWW"
    COUNTER=$(($COUNTER+1))
done

Now I just want to loop through the new "multidimensional" array and give the output like mysql table:

+------------------------------+
| Row 1    | Row 2  | Row 3    |
+------------------------------+
| Value    | Value  | Value    |
+------------------------------+

How can I do that?

  • The output of those dig commands may contain multiple lines (like dig www,google.com +short). Do you want to support that? – Stéphane Chazelas Sep 21 '16 at 12:14
  • Eh, no. I forgot to mention, that I filter out only the last line (in probably all cases it's the IP address) – Matt Backslash Sep 21 '16 at 12:15
  • @StéphaneChazelas I added the "filtering" in the question-code – Matt Backslash Sep 21 '16 at 12:19
  • 1
    See also: unix.stackexchange.com/q/310900/117549 – Jeff Schaller Sep 21 '16 at 12:38
5

Using perl's Text::ASCIITable module (also supports multi-line cells):

print_table() {
  perl -MText::ASCIITable -e '
    $t = Text::ASCIITable->new({drawRowLine => 1});
    while (defined($c = shift @ARGV) and $c ne "--") {
      push @header, $c;
      $cols++
    }
    $t->setCols(@header);
    $rows = @ARGV / $cols;
    for ($i = 0; $i < $rows; $i++) {
      for ($j = 0; $j < $cols; $j++) {
        $cell[$i][$j] = $ARGV[$j * $rows + $i]
      }
    }
    $t->addRow(\@cell);
    print $t' -- "$@"
}

print_table Domain 'Without WWW'    'With WWW' -- \
            "$@"   "${WOUT_WWW[@]}" "${WITH_WWW[@]}"

Where the WOUT_WWW and WITH_WWW arrays have been constructed as:

for domain do
  WOUT_WWW+=("$(dig +short "$domain")")
  WITH_WWW+=("$(dig +short "www.$domain")")
done

Which gives:

.---------------------------------------------------------------------.
| Domain            | Without WWW    | With WWW                       |
+-------------------+----------------+--------------------------------+
| google.com        | 216.58.208.142 |                 74.125.206.147 |
|                   |                |                 74.125.206.104 |
|                   |                |                 74.125.206.106 |
|                   |                |                 74.125.206.105 |
|                   |                |                 74.125.206.103 |
|                   |                |                  74.125.206.99 |
+-------------------+----------------+--------------------------------+
| stackexchange.com |  151.101.65.69 | stackexchange.com.             |
|                   |   151.101.1.69 |                   151.101.1.69 |
|                   | 151.101.193.69 |                 151.101.193.69 |
|                   | 151.101.129.69 |                 151.101.129.69 |
|                   |                |                  151.101.65.69 |
+-------------------+----------------+--------------------------------+
| linux.com         |  151.101.193.5 | n.ssl.fastly.net.              |
|                   |   151.101.65.5 | prod.n.ssl.us-eu.fastlylb.net. |
|                   |    151.101.1.5 |                   151.101.61.5 |
|                   |  151.101.129.5 |                                |
'-------------------+----------------+--------------------------------'
  • Wow. That's awesome! That's exactly what I was looking for. I already figured out a solution in bash, but this one is way better. Thank you! – Matt Backslash Sep 21 '16 at 12:52
0

I tried a lot of variations and done some researches. Following code is working great for me:

for DOMAIN in "${DOMAINS[@]}"; do
    printf "%-8s\n" "${DOMAIN}"
done | sed -e 's/|/_|g' | column -t -s '_' | awk '1;! (NR%1){print "---------";}'

Just looping through my array. I'm using sed because I have a delimiter in my array-values to split them up. But column was that what I was searching for.

  • 1
    ! (NR%1) is a strange obfuscating way of saying true... – JJoao Sep 21 '16 at 15:01
0
function printTable()
{
    local -r delimiter="${1}"
    local -r data="$(removeEmptyLines "${2}")"

    if [[ "${delimiter}" != '' && "$(isEmptyString "${data}")" = 'false' ]]
    then
        local -r numberOfLines="$(wc -l <<< "${data}")"

        if [[ "${numberOfLines}" -gt '0' ]]
        then
            local table=''
            local i=1

            for ((i = 1; i <= "${numberOfLines}"; i = i + 1))
            do
                local line=''
                line="$(sed "${i}q;d" <<< "${data}")"

                local numberOfColumns='0'
                numberOfColumns="$(awk -F "${delimiter}" '{print NF}' <<< "${line}")"

                # Add Line Delimiter

                if [[ "${i}" -eq '1' ]]
                then
                    table="${table}$(printf '%s#+' "$(repeatString '#+' "${numberOfColumns}")")"
                fi

                # Add Header Or Body

                table="${table}\n"

                local j=1

                for ((j = 1; j <= "${numberOfColumns}"; j = j + 1))
                do
                    table="${table}$(printf '#| %s' "$(cut -d "${delimiter}" -f "${j}" <<< "${line}")")"
                done

                table="${table}#|\n"

                # Add Line Delimiter

                if [[ "${i}" -eq '1' ]] || [[ "${numberOfLines}" -gt '1' && "${i}" -eq "${numberOfLines}" ]]
                then
                    table="${table}$(printf '%s#+' "$(repeatString '#+' "${numberOfColumns}")")"
                fi
            done

            if [[ "$(isEmptyString "${table}")" = 'false' ]]
            then
                echo -e "${table}" | column -s '#' -t | awk '/^\+/{gsub(" ", "-", $0)}1'
            fi
        fi
    fi
}

function removeEmptyLines()
{
    local -r content="${1}"

    echo -e "${content}" | sed '/^\s*$/d'
}

function repeatString()
{
    local -r string="${1}"
    local -r numberToRepeat="${2}"

    if [[ "${string}" != '' && "${numberToRepeat}" =~ ^[1-9][0-9]*$ ]]
    then
        local -r result="$(printf "%${numberToRepeat}s")"
        echo -e "${result// /${string}}"
    fi
}

function isEmptyString()
{
    local -r string="${1}"

    if [[ "$(trimString "${string}")" = '' ]]
    then
        echo 'true' && return 0
    fi

    echo 'false' && return 1
}

function trimString()
{
    local -r string="${1}"

    sed 's,^[[:blank:]]*,,' <<< "${string}" | sed 's,[[:blank:]]*$,,'
}

SAMPLE RUNS

$ cat data-1.txt
HEADER 1,HEADER 2,HEADER 3

$ printTable ',' "$(cat data-1.txt)"
+-----------+-----------+-----------+
| HEADER 1  | HEADER 2  | HEADER 3  |
+-----------+-----------+-----------+

$ cat data-2.txt
HEADER 1,HEADER 2,HEADER 3
data 1,data 2,data 3

$ printTable ',' "$(cat data-2.txt)"
+-----------+-----------+-----------+
| HEADER 1  | HEADER 2  | HEADER 3  |
+-----------+-----------+-----------+
| data 1    | data 2    | data 3    |
+-----------+-----------+-----------+

$ cat data-3.txt
HEADER 1,HEADER 2,HEADER 3
data 1,data 2,data 3
data 4,data 5,data 6

$ printTable ',' "$(cat data-3.txt)"
+-----------+-----------+-----------+
| HEADER 1  | HEADER 2  | HEADER 3  |
+-----------+-----------+-----------+
| data 1    | data 2    | data 3    |
| data 4    | data 5    | data 6    |
+-----------+-----------+-----------+

$ cat data-4.txt
HEADER
data

$ printTable ',' "$(cat data-4.txt)"
+---------+
| HEADER  |
+---------+
| data    |
+---------+

$ cat data-5.txt
HEADER

data 1

data 2

$ printTable ',' "$(cat data-5.txt)"
+---------+
| HEADER  |
+---------+
| data 1  |
| data 2  |
+---------+

REF LIB at: https://github.com/gdbtek/linux-cookbooks/blob/master/libraries/util.bash

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.