Alternative to Cat out of a bash script? - arrays

i have an issue with the following.
exec 3<>/dev/tcp/$1/37491
echo -ne 060e2b3 00$hexdec$cmdhex | perl -pe 's/([0-9a-f]{2})/chr hex $1/gie' >&3
cat <&3
i have a server in which i send a hex string to with the port / tcp connection made. BUT since i am using putty through a terminal my first issue is that the XML response back always says PuTTY and it doesnt escape. I also need to put the replies back sometimes in an array and i have tried
array=`cat <&3`
echo "Array items:"
for item in ${array[*]}
do
printf " %s\n" $item
done
and i believe since the cat is not exiting properly it just stays open the array is not done?
thanks for the advanced help

Do you need specify a timeout?
while read -t 5 line <&3; do
echo "$line"
(( Lines++ ))
done
exec 3>&-

Perhaps you need to close the TCP/IP socket?
exec 3>&-

Related

process file line by line does not work in ksh

This looks simple but i am not sure why it wont read beyond first line if I try to do any processing on data i read from file.
code:
while IFS="" read -r line
do
u=`echo $line | awk '{print $4}'`
h=`echo $line | awk '{print $2}'|cut -f1 -d'.'`
echo "$h : $u"
ssh $h grep $u /etc/shadow
done < "/var/tmp/user_data"
user_data is a file with one line for each user/system like:
xxx unixhost01 xxx admin69 xxx... ....
xxx host xxx uid xxx... ...
...
...
when i run this code it only works on first line then exit. debug in shell shows no issues. when i run it without the ssh operation/command it processes whole data file.
shell is ksh:
# ps
PID TTY TIME CMD
1424 pts/138 0:00 ps
18521 pts/138 0:02 ksh
on executing it only prints (the first line):
unixhost01 : admin69
admin69:$1$gFfcEQETGZAo6W0:17599:0:90:10:::
any idea?
The problem lies in ssh itself since it consumes standard input so the next time you loop around to get another line, there aren't any left. You can verify this by changing your command to:
ssh $h cat
and seeing that it outputs the rest of your file during the first ssh session.
You can fix this in at least two ways, the first by simply disconnecting your ssh from standard input:
ssh $h grep $u /etc/shadow </dev/null
The second (needed if you actually want to interact with the target box) is to use a different file handle for the input file stream:
while IFS="" read -u3 -r line ; do # reads file #3
blah blah blah
done 3</var/tmp/user_data # sends data via file #3

Populate array to ssh in bash

Just some background, I have a file with 1000 servers in it new line delimted. I have to read them to an array the run about 5 commands over SSH. I have been using heredoc notation but that seems to fail. Currently I get an error saying the host isn't recognized.
IFS='\n' read -d '' -r -a my_arr < file
my_arr=()
for i in "${my_arr[#]}"; do
ssh "$1" bash -s << "EOF"
echo "making back up of some file"
cp /path/to/file /path/to/file.bak
exit
EOF
done
I get output that lists the first server but then all the ones in the array as well. I know that I am missing a redirect for STDIN that causes this.
Thanks for the help.
Do you need an array? What is wrong with:
while read -r host
do
ssh "$host" bash -s << "EOF"
echo "making back up of some file"
cp /path/to/file /path/to/file.bak
EOF
done < file
To be clear -- the problem here, and the only problem present in the code actually included in your question, is that you're using $1 inside your loop, whereas you specified $i as the variable that contains the entry being iterated over on each invocation of the loop.
That is to say: ssh "$1" needs to instead by ssh "$i".

Reading a file into an associative array in Bash

I'm trying to read the information of a structured file into an associative array using Bash script. The file contains in each line the name of a person and its address, separated by a "|". For example:
person1|address of person1
person2|address of person2
...
personN|address of personN
I tried to do this using the script below. Within the WHILE loop, the information is being printed. However, in the FOR loop the information is not being printed. It seems that the information is not being stored in the associative array outside of the WHILE loop.
What am I doing wrong? Why this is not working? Is there more efficient ways to do that?
#!/bin/bash
declare -A address
cat adresses.txt | while read line
do
name=`echo $line | cut -d '|' -f 1`
add=`echo $line | cut -d '|' -f 2`
address[$name]=$add
echo "$name - ${address[$name]}"
done
for name in ${!address[*]}
do
echo "$name - ${address[$name]}"
done
Wrong and useless usage of cut
#!/bin/bash
declare -A address
while IFS=\| read name add
do
address[$name]=$add
done < adresses.txt
for name in ${!address[*]}
do
echo "$name - ${address[$name]}"
done
cat addresses.txt | while read line
do
...
done
Shell commands in a pipelines are executed in subshells. Variables set in subshells aren't visible the parent shell.
You can fix this by replacing the pipelines with a redirection.
while read line
do
...
done < addresses.txt
Extending the accepted answer to resolve the OP's comment:
#!/bin/bash
declare -A address
while IFS='|' read name add
do
address[$name]=$add
echo "$name - ${address[$name]}"
done < adresses.txt
for name in "${!address[#]}"
do
echo "$name - ${address[$name]}"
done

Handle ctrl +d programmatically?

I am trying to execute the following perl script.
##some code
$command = "nail -s this is a test $email";
system($command);
##some code
when I run this script, it hangs until I press CtrlD. after pressing CtrlD I get the desired result. My question is how can I hardcode CtrlD in my script?
I suppose you call mailx. nail ist most likely an alias. It expects input from STDIN, which is ended with CtrlD. You could workaround like this to send an empty mail:
$command = 'echo "" | nail -s SUBJECT ' . $email;
The mail program expects an . on a line alone to show it is the end of the message
Just make sure your $email contains a \n. and it should no longer hang.
The usual solution is to redirect it to read from /dev/null
Try to use this :
mail -s "Hello Test" -a Attachment email-address </dev/null
or, if you have any email body
mail -s "Hello Test" -a Attachment email-address <emailbodyfile.txt

How to send array values by mail

in linux scripting,
is there a way to use mail function to one time send array values??
function my_mail_function(){
# send array values
mail array_values_here "mymail#domain.tld" ;
}
Thank you
You can step through an array with just a little bit of bash code.
#!/bin/bash
# Here's a simple array...
a=(one two three)
# The brackets encapsulate multiple commands to feed to the stdin of sendmail
(
echo "To: Mister Target <target#example.com>"
echo "From: Julio Fong <jf#example.net>"
echo "Subject: Important message!"
echo ""
count=1
for item in ${a[#]}; do
printf "Value %d is %s\n" "$count" "$item"
((count++))
done
echo ""
) | /usr/sbin/sendmail -oi -fjf#example.net target#example.com
Note that it'll be safer to use sendmail directly rather than relying on the availability and configuration of a mail or Mail command. Your sendmail binary may not be in the same place as mine; if /usr/sbin/ doesn't work for you, check /usr/libexec/. It'll depend on the distribution of Linux you're running.
The proper way to use mail is:
mail -s "subject here" recipient1 recipient2 ...
the command reads the email body from stdin so you can format it how you like and read it in from a pipe or a here-doc or a file or ...
function my_mail_function(){
printf "%s\n" "${array_var[#]}" | mail -s "array values" mymail#domain.tld
}

Resources