Search code examples
linuxshellsh

I'm having a strange Shell problem that I can't understand


Because of a specific requirement scenario, I wanted to write a Shell script to monitor the DNS used by my Linux host. Here's how I wrote it:

#! /usr/bin/bash

NETWORKING_DNS=$(nmcli dev show |grep DNS|awk '{print $2}')
echo "Current DNS: "
echo "$NETWORKING_DNS"

No problems so far, it outputs something like this:

xxx@xxx ~:$ bash script.sh
Current DNS:
1.1.1.1
1.0.0.1

Because I have other information to output, I wanted it to display it on one line, so I changed it to the following:

echo "Current DNS: $NETWORKING_DNS"

But when I was executing this script, something strange happened and its output became like this:

xxx@xxx ~:$ bash script.sh
Current DNS: 1.1.1.1
1.0.0.1

Why??

I thought it would output like this:

Current DNS: 1.1.1.1 1.0.0.1

I don't know why this is happening. I've tried a number of things, such as using the -n option:

echo -n "Current DNS: $NETWORKING_DNS"

Or

printf "Current DNS: %s" "$NETWORKING_DNS"

None of them achieve the result I want.

Can anyone tell me why this is? (It's an "unimportant" question, but I'm kind of curious.)

My linux host info:

xxx@xxx ~:$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="20.04.2 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.2 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal

xxx@xxx ~:$ bash --version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

echo -n "Current DNS: $NETWORKING_DNS"

or

echo -ne "Current DNS: $NETWORKING_DNS"

or

printf "Current DNS: %s" "$NETWORKING_DNS"

It doesn't works.


Solution

  • As mentioned in the other answers, the root cause is that there is a newline inside your NETWORKING_DNS.

    You set up the content of that variable by processing it with AWK (print $2). There are several options that influence the output of AWK. (You can read the documentation of AWK for the details.) But the summary is: AWK is doing the print $2-action for every record it gets from the pipe. AWK separates the output of each action by printing the OutputRecordSeparator (or ORS).

    The ORS is by default a newline, but you can tweak it to something different, e.g. replace your line in your script with:

    NETWORKING_DNS=$(nmcli dev show |grep DNS|awk -v ORS=" " '{print $2}')
    

    to change the ORS to space.

    How it works:

    • the invocation of awk sets the ORS variable to space instead of the default newline using the -v option