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.
2
Answers
Variable contains
1.1.1.1
followed by a newline character followed by1.0.0.1
.The newline character when printed starts a new line. Advances cursor position to the next empty line, optionally shifting terminal output one line up, depending on the terminal, and moves cursor position to column 0.
The variable contains a newline character, it will be printed when variable content is printed, no matter the method.
Tip: you can debug variables with
declare -p NETWORKING_DNS
. Unquoted variable expansions undergo word splitting (and filename expansion), which joins words split by spaces – so you mightecho $NETWORKING_DNS
. Research ASCII, shell quoting, word splitting expansion, filename expansion. Check your scripts with shellcheck. To replace newline with a space, you can usetr 'n' ' '
orpaste -sd ' '
, seeman tr
andman paste
.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 theprint $2
-action for every record it gets from the pipe. AWK separates the output of each action by printing the OutputRecordSeparator (orORS
).The
ORS
is by default a newline, but you can tweak it to something different, e.g. replace your line in your script with:to change the ORS to space.
How it works:
-v
option