Bash complete with "#"-sign - bash

I am trying to create an autocomplete script for scp.
The script reads the user and hostname from my .ssh/config file
My .ssh/config file looks like:
Host host1
HostName host1
User userA
port 22
Host host2
HostName host2
User userB
port 22
Host host3
HostName host3
User userB
port 22
My .autocomplete_scp.sh file is:
# SSH
function _scp_completion() {
pcregrep -o -M 'HostName [a-zA-Z.]+[\n\t\s]+User [a-zA-Z]+'
$HOME/.ssh/config | awk 'NR % 2 == 1 { o=$2 ; next } { print $2"#"o}'
}
complete -W "$(_scp_completion)" scp
I source this file in my bashrc.
Now when I type userA and press Tab, the autocomplete function will give me userA#host1. When I type userB and hit Tab, the autocomplete function will give me userB#, but I am not able to get the full string (userB#host2 or userB#host3).
It also doesn't work when I type userA#h and hit the Tab button twice. So it seems to get stuck due to the # sign.
(When I remove the # sign from the _scp_completion function it works fine.)
Any ideas to fix this? Thanks!

The easy way to make it work is to remove '#' from $COMP_WORDBREAKS or Bash would handle # by itself. You can try like this:
COMP_WORDBREAKS=${COMP_WORDBREAKS//#}
complete -W 'userA#host1 userB#host2 userB#host3' scp
According to bash doc:
COMP_WORDBREAKS
The set of characters that the readline library treats as word separators when performing word completion.

Related

reuse numerical value from a text entry in subsequent entries

I'm trying to automate a procedure and to create the output file that I need. So far everything is going well, but I cannot figure out how to take the number at the end of one row and fill it in for rows after it.
I've tried solutions using awk, sed, etc, but so far, I can't seem to figure this out even with the helps of many googles.
POP-Test-01
10.10.10.10
User: User
Pass: Pass
POP-Test-02
10.10.10.11
User: User
Pass: Pass
POP-Test-03
10.10.10.12
User: User
Pass: Pass
But I want it to take the numerical values from the first line, and append it to the user and pass lines. But for the pass line, I'd like to add it twice.
POP-Test-01
10.10.10.10
User: User01
Pass: Pass0101
POP-Test-02
10.10.10.11
User: User02
Pass: Pass0202
POP-Test-03
10.10.10.12
User: User03
Pass: Pass0303
These are only examples, but the last two digits of the hostname(ex. POP-Test-03) will always be numerical digits.
Edit:
I've had some requests for more details. Sorry about that guys, so here is the skinny. Please note that all values are fake, these come from an input file. I just used the most generic values I could think of.
The input is a text file with only the values in the top example.
So I run a script that deploys instances and the only output I get from the deployment script is the Hostname and the IP address. I know it's not clean, but below is how I'm adding the user and password. But the user and pass are always the same between each batch of servers with only the number of the server being appended to the user and the password(twice). I'm doing this because an application we use requires the input of:
HOSTNAME
IP
User: (username)
Pass: (password)
(empty line)
Normally I have to enter these manually which is time consuming and I was hoping not necessary since I've started it with the commands below in a script I am trying to build to automate the process.
So I start with this:
POP-Test-01
10.10.10.10
And I'm trying to get to this:
POP-Test-01
10.10.10.10
User: User01
Pass: Pass0101
awk '/([0-9]{1,3}[\.]){3}[0-9]{1,3}/{print;print "User\:
Train";next}1' DeploymentDetails2.txt | tee DeploymentDetails2.txt<br/>
awk '/User/{print;print "Pass\: Training";next}1'
DeploymentDetails2.txt | tee DeploymentDetails2.txt<br/>
awk '/Pass/{print;print "\n";next}1' DeploymentDetails2.txt | tee
DeploymentDetails.txt<br/>
This appears to produce what you are looking for:
#!/bin/bash
HOST="POP-Test-"
IP=10
for i in {01..99} ; do
echo ${HOST}${i}
echo "10.0.10.${IP}"
echo "User: User${i}"
echo "Pass: Pass${i}${i}"
echo
let IP++
done
As you did not specify that there was an input file, I took the liberty of generating the ending number in the script, and reusing it in the user and pass lines.

Ssh not working when host is taken using grep

When I'm hardcoding i. e.
server1=ip-10.237.40.10-aws-n-myhost
ssh - i /home/<passwordfile> akhil#$server1
It is working,but when I'm greping the host from other file its not working
Eg:
server2=$(grep - e host /home/akhil/configuration. File | awk FS, '{print $2} ' )
echo $server2
ssh - i /home/<passwordfile> akhil#$server2
While printing server 2 is fine, but when it is used in ssh I'm getting a error saying : not known host name.
I want to automate the script with a configuration file so that when ever the cluster changes I could simply change the ip address in configfile instead of changing in all my scripts.
I need help in this.
Thanks

Shell / Korn script - set variable depending on hostname in list

I need to write a korn script that depending on the host the script is running on, will set a deployment directory (so say 5 hosts deploy the software to directory one and five other hosts deploy to directory two).
How could I do this - I wanted to avoid an if condition for every host like below
IF [hostname = host1] then $INSTALL_DIR=Dir1
ELSE IF [hostname = host2] then $INSTALL_DIR=Dir1
and would prefer to have a list of say Directory1Hosts and Directory2Hosts which contains all the hosts valid for each directory, and then I would just check if the host the script is running on is in my Directory1Hosts or Directory2Hosts (so only two IF conditions instead of 10).
Thanks for your help - have been struggling to find how to do effectively a contains clause.
Use a case statement:
case $hostname in
host1) INSTALL_DIR=DIR1 ;;
host2) INSTALL_DIR=DIR2 ;;
esac
or use an associative array
install_dirs=([host1]=DIR1 [host2]=DIR2)
...
INSTALL_DIR=${install_dirs[$hostname]}
When you want to have configuration and code apart, you can make a config directory: one file with hosts for each install dir.
# cat installdirs/Dir1
host1
host2
With these files your code can be
INSTALL_DIR=$(grep -Flx "${hostname}" installdirs/* | cut -d"/" -f2)

Output the file in way we wanted

I have ssh config file which contains so many servers from google,aws and some remote servers.I wanted to have a bash function that will output only the Host and the HostName of the server so I dont have to remember there public DNS to check my webapps.
Sample Server Config in my ssh config looks like this
Host aws_server
User rand
HostName 65.2.25.152
Port 8000
IdentityFile PEM PATH
ServerAliveInterval 120
ServerAliveCountMax 30
I want the output like
aws_server 65.2.25.152
for all the servers
Using sed
sed '/^Host/{s/[^ ]* //;:1;N;s/\n.*HostName */\t/;t2;b1;:2;p};d' file
aws_server 65.2.25.152
Modified version that's more robust for multiple hosts,missing HostNames
sed ':1;s/\(.*\n\|^\)Host *//;N;s/\n.*HostName */\t/;t2;$!{b1;:2;p};d' file
using awk
awk '{if($1=="Host")k=$2;if($1=="HostName")printf("%s\t%s\n",k,$2)}' file
I would use awk for this:
awk '
# Save the host when we see it.
/^Host/ {
host=$2
next
}
# If we have a host and are on a HostName line
host && $1 == "HostName" {
# Print the Host and HostName values
printf "%s"OFS"%s\n", host, $2
host=""
next
}
# If we have a HostName without a Host clear the host (should not happen but just to be safe)
$1 == "HostName" {
host=""
}
' .ssh/config

shell script display grep results

I need some help with displaying how many times two strings are found on the same line! Lets say I want to search the file 'test.txt', this file contains names and IP's, I want to enter a name as a parameter when running the script, the script will search the file for that name, and check if there's an IP-address there also. I have tried using the 'grep' command, but I don't know how I can display the results in a good way, I want it like this:
Name: John Doe IP: xxx.xxx.xx.x count: 3
The count is how many times this line was found, this is how my grep script looks like right now:
#!/bin/bash
echo "Searching $1 for the Name '$2'"
result=$(grep "$2" $1 | grep -E "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)")
echo $result
I will run the script like 'sh search test.txt John'.
I'm having trouble displaying the information I get from the grep command, maybe there's a better way to do this?
EDIT:
Okey, I will try to explain a little better, let's say I want to search a .log file, I want a script to search that file for a string the user enters as a parameter. i.e if the user enters 'sh search test.log logged in' the script will search for the string "logged in" within the file 'test.log'. If the script finds this line on the same line as a IP-address the IP address is printed, along with how many times this line was found.
And I simply don't know how to do it, I'm new to shell scripting, and was hoping I could use grep along with regular expressions for this! I will keep on trying, and update this question with an answer if I figure it out.
I don't have said file on my computer, but it looks something like this:
Apr 25 11:33:21 Admin CRON[2792]: pam_unix(cron:session): session opened for user 192.168.1.2 by (uid=0)
Apr 25 12:39:01 Admin CRON[2792]: pam_unix(cron:session): session closed for user 192.168.1.2
Apr 27 07:42:07 John CRON[2792]: pam_unix(cron:session): session opened for user 192.168.2.22 by (uid=0)
Apr 27 14:23:11 John CRON[2792]: pam_unix(cron:session): session closed for user 192.168.2.22
Apr 29 10:20:18 Admin CRON[2792]: pam_unix(cron:session): session opened for user 192.168.1.2 by (uid=0)
Apr 29 12:15:04 Admin CRON[2792]: pam_unix(cron:session): session closed for user 192.168.1.2
Here is a simple Awk script which does what you request, based on the log snippet you posted.
awk -v user="$2" '$4 == user { i[$11]++ }
END { for (a in i) printf ("Name: %s IP: %s count: %i\n", user, a, i[a]) }' "$1"
If the fourth whitespace-separated field in the log file matches the requested user name (which was passed to the shell script as its second parameter), add one to the count for the IP address (from field 11).
At the end, loop through all non-zero IP addresses, and print a summary for each. (The user name is obviously whatever was passed in, but matches your expected output.)
This is a very basic Awk script; if you think you want to learn more, I urge you to consult a simple introduction, rather than follow up here.
If you want a simpler grep-only solution, something like this provides the information in a different format:
grep "$2" "$1" |
grep -o -E '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)' |
sort | uniq -c | sort -rn
The trick here is the -o option to the second grep, which extracts just the IP address from the matching line. It is however less precise than the Awk script; for example, a user named "sess" would match every input line in the log. You can improve on that slightly by using grep -w in the first grep -- that still won't help against users named "pam" --, but Awk really gives you a lot more control.
My original answer is below this line, partly becaus it's tangentially useful, partially because it is required in order to understand the pesky comment thread below.
The following
result=$(command)
echo $result
is wrong. You need the second line to be
echo "$result"
but in addition, the detour over echo is superfluous; the simple way to write that is simply
command

Resources