How to assign a color to a variable within a bash function - bash

I have following script where i want to to print the command Variable SMB into the RED colour within a bash function but that's not working.
Below is the Script:
Script:
#!/bin/bash
read -rsp $'Please Enter password below: ' SSHPASS
echo -n ""
export SSHPASS
NC='\033[0m'
RED='\033[0;31m'
remote_connect() {
target_host=$1
sshpass -e ssh -q "${target_host}" "true" -o StrictHostKeyChecking=no -o ConnectTimeout=60 2>>/dev/null
if [[ $? -eq 0 ]]
then
SMB=$(sshpass -e ssh -q -t "$target_host" "sudo smbstatus |grep ^Samba")
printf "%-35s %15s\n" "$target_host" "${RED}${SMB}${NC}"
else
printf "%-35s %15s\n" "$target_host" "Unable to get the ssh connection"
fi
} 2>/dev/null
export -f remote_connect
< host_list xargs -P5 -n1 -d'\n' bash -c 'remote_connect "$#"' --
Result:
tdi1990.colx.fox.com \033[0;31m Samba version 4.9.1 \033[0m \n
tdi1856.colx.fox.com \033[0;31m Samba version 4.9.1 \033[0m \n
tdi1993.colx.fox.com \033[0;31m Samba version 4.9.1 \033[0m \n
If i use echo like below it works, but then the lifet and right justify as i am trying with print that's not possible with echo.
echo -e "$target_host" "${RED}${SMB}${NC}"
Expected:
Second column that is Samba version 4.9.1 should be printed in Red color.

This should achieve what you expected :
NC=$'\033[0m'
RED=$'\033[0;31m'

Related

Bash Script for using grep in an if statement with a for loop

I am trying to make my bash script ssh into each server and then grep Selinux=enforcing/replace with Selinux=permissive. The issue I am facing is it checks the first server and but not the second server. I believe it arises from my if statement.
#!/bin/bash
selinux_path=/opt/configtest
hosts=(server1 server2)
for my_hosts in "${hosts[#]}"
do
ssh -q -o "StrictHostKeyChecking no" root#${my_hosts} "
if [ $(grep -c SELINUX=enforcing $selinux_path) -ne 0 ]
then
echo "------------------------------------------------"
echo "${my_hosts}"
echo "------------------------------------------------"
sed -i 's/SELINUX=enforcing/SELINUX=permissive/g' ${selinux_path}
echo "Selinux has been changed to permissive"
cat ${selinux_path}
else
echo "------------------------------------------------"
echo "${my_hosts}"
echo "------------------------------------------------"
echo "Selinux has already been changed to permissive"
cat ${selinux_path}
fi
"
done
You can't nest " inside ". If you want to give multiline input to ssh, the easiest way is with a here-doc.
#!/bin/bash
selinux_path=/opt/configtest
hosts=(server1 server2)
for my_hosts in "${hosts[#]}"
do
ssh -q -o "StrictHostKeyChecking no" root#${my_hosts} <<EOF
if grep -q SELINUX=enforcing "$selinux_path"
then
echo "------------------------------------------------"
echo "${my_hosts}"
echo "------------------------------------------------"
sed -i 's/SELINUX=enforcing/SELINUX=permissive/g' ${selinux_path}
echo "Selinux has been changed to permissive"
cat "${selinux_path}"
else
echo "------------------------------------------------"
echo "${my_hosts}"
echo "------------------------------------------------"
echo "Selinux has already been changed to permissive"
cat "${selinux_path}"
fi
EOF
done
Did you try to specify the full path for grep, echo, sed and cat?

bash to pass array to ssh to another server

In the below bash I am trying to pass the ${array[$i]} to ssh after changing to a specific directory, but ${array[$i]} it is not recognized? The goal is to use the id in ${array[$i]} (there may be more than 1) to further go into that directory. The bash seems to work as expected except for the ${array[$i]} not be passed.
bash
readarray -t array <<< "$(printf '%s\n' $id)"
for ((i=0; i<${#array[#]}; i++ )) ; do
echo "${array[$i]}"
done
sshpass -f file.txt ssh -o strictHostKeyChecking=no -t xxx#xxx "${array[$i]}" 'cd path/to/folder/"$array[$i]" && exec bash -l'
echo ${array[$i]}
maybe?
readarray -t array <<< "$(printf '%s\n' $id)"
for ((i=0; i<${#array[#]}; i++ )) ; do
echo "${array[$i]}"
done
for i in "${array[$i]} ; do
sshpass -f file.txt ssh -o strictHostKeyChecking=no -t xxx#xxx "${array[$i]}" 'cd path/to/folder && exec bash -l'
done
contents of array[$i] ---- array[$i] will be different in number each time but the format will always be the same ----
00-0000-xxx-xxx-xxx
00-0001-yyy-yyy-yyy
desired ssh
cd path/to/folder/00-0000-xxx-xxx-xxx && cp *.txt* /home/location
cd path/to/folder/00-0000-yyy-yyy-yyy && cp *.txt* /home/location
Here, we generate a single remote that runs (cd ... && exec cp) for each array element, with each in a subshell to prevent the cd from having side effects on subsequent elements' commands:
printf -v cmd_q '(cd /path/to/folder/%q && exec cp -- *.txt* /home/location)\n' "${array[#]}"
sshpass -f file.txt ssh -o strictHostKeyChecking=no -t xxx#xxx "$cmd_q"
The exec is a minor performance enhancement, consuming the subshell started with the parenthesis by replacing it with the cp process.
The %q placeholder in the printf format string gets substituted with the individual array values.

How to make runuser correctly forward all command line arguments, instead of trying to interpret them?

I got this simple script:
#!/bin/bash
SOURCE_USER=$USER
DESTINE_USER=$1
id -u $SOURCE_USER > /dev/null 2>&1
if [ "$?" == "1" ] || [ -z $SOURCE_USER ]
then
printf "Error: Invalid source user '$SOURCE_USER'\\n"
exit 1
fi
if [ -z $DESTINE_USER ]
then
printf "Error: Invalid destine user '$DESTINE_USER'\\n"
exit 1
fi
SOURCE_GROUPS=$(id -Gn ${SOURCE_USER} | sed "s/${SOURCE_USER} //g" | sed "s/ ${SOURCE_USER}//g" | sed "s/ /,/g")
SOURCE_SHELL=$(awk -F : -v name=${SOURCE_USER} '(name == $1) { print $7 }' /etc/passwd)
id -u $DESTINE_USER > /dev/null 2>&1
if [ "$?" == "1" ]
then
printf "Creating destine user %s\\n" "$DESTINE_USER"
useradd --groups ${SOURCE_GROUPS} --shell ${SOURCE_SHELL} --create-home ${DESTINE_USER}
passwd ${DESTINE_USER}
xhost '+si:localuser:$DESTINE_USER'
sudo usermod -G "$SOURCE_USER" "$DESTINE_USER"
else
printf "Updating destine user '%s' with groups '%s' and shell '%s'\\n" "$DESTINE_USER" "$SOURCE_GROUPS" "$SOURCE_SHELL"
sudo usermod -a -G "$SOURCE_GROUPS" "$DESTINE_USER"
sudo chsh -s "$SOURCE_SHELL" "$SOURCE_USER"
fi
sudo runuser sublime_vanilla -c "${#:2}"
I run it like this:
$ bash run_as_user.sh sublime_vanilla /usr/bin/subl -n "./New Empty File"
But when I run it, I got this error:
runuser: invalid option -- 'n'
Try 'runuser --help' for more information.
But if I replace sudo runuser sublime_vanilla -c "${#:2}" with sudo runuser sublime_vanilla -c "\"$2\" \"$3\" \"$4\" \"$5\" \"$6\" \"$7\" \"$8\" \"${#:9}\""
Then, Sublime Text correctly opens the file "./New Empty File" in a new window.
How to make runuser correctly understand all argument with a variable number of command line arguments, i.e., without hard coding "\"$2\" \"$3\" \"$4\" ..."?
This is slightly different from your last question because you have to make the expansion of the arguments into a single string for the -c option.
The bash printf formatter %q is your friend here:
cmd=$( printf '%q ' "${#:2}" )
sudo runuser sublime_vanilla -c "$cmd"
On the other hand, a quick perusal through the runuser man page suggests:
sudo runuser -u sublime_vanilla "${#:2}"
Another thought: sudo runuser -u sublime_vanilla -- "${#:2}" with the double hyphens to indicate the end of the runuser options.

Passing -e and -n as positional parameters in Bash

I've recently been working with positional parameters in some bash scripts and I've noticed that -e and -n do not appear to be passed as positional parameters. I've been searching through documentation but haven't been able to figure out why. Consider the following short scripts:
#!/bin/bash
# test.sh
echo $#
echo $1
echo $2
echo $3
echo $4
echo $5
exit
Running the command: # ./test.sh -e -f -c -n -g outputs:
-f -c -n -g
-f
-c
-g
./test.sh -n -f -c -e -g outputs:
-f -c -e -g-f
-c
-g
Why do -e and -n not appear in "$#"? -e appears to pass as an empty parameter and -n appears to remove the following endline. Furthermore I noticed that these parameters are accounted for when echoing $#. Does anyone know why -e and -n behave differently than any other parameters.
The -e is passed like an argument to echo and then is comsumed by it.
Try this instead :
#!/bin/bash
printf '%s\n' "$1"
printf '%s\n' "$2"
printf '%s\n' "$3"
printf '%s\n' "$4"
printf '%s\n' "$5"
Output :
-e
-f
-c
-n
-g
Check help echo | less +/-e
You can use :
echo -- "$1"
too
Another solution
using bash here document
#!/bin/bash
cat<<EOF
$1
$2
$3
$4
$5
EOF

reading from serial using shellscript

I have a serial port device that I would like to test using Linux command line.
And if I run the following command from terminal, it gives output
cat < /dev/ttyS0 &
This command opens the serial port and relays what it reads from it to its stdout.So, I tried it from shell script file but it is not working
fName="test.txt";
awk '
BEGIN { RS = "" ; FS = "\n" }
{
address = '/dev/ttyS0';
system("cat < " address );
}
END {
}' "$fName";
But it is not working and giving output.How can I listen to communication between a process and a serial port? Thanks
Using awk timeouts
I've successfully read something under dash, be using GAWK_READ_TIMEOUT environment variable:
out=`GAWK_READ_TIMEOUT=3000 awk '{print}' </dev/ttyS0 & sleep 1 ; echo foo >/dev/ttyS0`
On my terminal, this output:
echo "$out"
foo
Password:
or
echo "$out"
Login incorrect
testhost login:
Using bash timeouts
You could use FD under bash as:
exec 5>/dev/ttyS0
exec 6</dev/ttyS0
while read -t .1 -u 6 line;do
echo $line
done
or, to read unfinished lines:
while IFS= read -d '' -t .1 -u 6 -rn 1 char;do
echo -n "$char"
done
echo
So you could:
echo 'root' >&5
while IFS= read -d '' -t .1 -u 6 -rn 1 char;do
echo -n "$char"
done
echo 'password is 1234' >&5
while IFS= read -d '' -t .1 -u 6 -rn 1 char;do
echo -n "$char"
done
... Once done, you could close FD by running:
exec 6<&-
exec 5>&-
Sample bash poor terminal script
I've logged and test some commands with:
#!/bin/bash
exec 5>/dev/ttyS0
exec 6</dev/ttyS0
readbuf() {
while IFS= read -d '' -t .1 -u 6 -rn 1 char;do
echo -n "$char"
done
};
while [ "$cmd" != "tquit" ] ;do
readbuf
read cmd
echo >&5 "$cmd"
done

Resources