Adding a string to the front of array loop? - arrays

#!/bin/bash
#OLDIFS=$IFS
IFS=$'\r'
fortune_lines=($(fortune | fold -w 90))
#Screen_Session=$"{mainscreen}"
Screen_Session=`screen -ls|grep "\."|grep "("|awk '{print $1}'`
Screen_OneLiner=$(screen -p 0 -S ${Screen_Session} -X stuff "`printf "${fortune_lines[#]}\r"`")
#IFS=$OLDIFS;
for var in "${Screen_OneLiner[#]}"
do
echo "${var}"
done
ok this script works (sorta). I need to at the string "say " to front of the entire array index. Currently I can only get it to print out "say " to the first line.

We need not complicate things with contraptions like arrays - we can let good old sed do the job.
#!/bin/bash
fortune_lines=$(fortune | fold -w 90 | sed 's/^/say /')
Screen_Session=`screen -ls|grep "\."|grep "("|awk '{print $1}'`
screen -p 0 -S $Screen_Session -X stuff "$fortune_lines"

Related

Using "comm" to find matches between two arrays

I have two arrays, I am trying to find matching values using comm. Array1 contains some additional information in each element that I strip out for the comparison. However, I would like to keep that information after the comparison is complete.
For example:
Array1=("abc",123,"hello" "def",456,"world")
Array2=("abc")
declare -a Array1
declare -a Array2
I then compare the two arrays:
oldIFS=$IFS IFS=$'\n\t'
array3=($(comm -12 <(echo "${Array1[*]}" | awk -F "," {'print $1'} | sort) <(echo "${Array2[*]}" | sort)))
IFS=$oldIFS
Which finds the match of abc:
echo ${test3[0]}
abc
However what I want is remaining values from array1 that were not part of my comm statement.
abc,123,hello
EDIT: For more clarification
The arrays in this example are populated with dummy data.
My real example is pulling information from server logs which I am saving into array1. array1 contains (userIDs,hostIPs,count) that I want to cross reference against a list of userID's (array2). My goal is to find out what userIDs exsist in array1 and array2 and save those ID's with the additional information from array1 (hostIPs,count) into array3
array1 is populated from a variable that is is the results of a curl command that generates a splunk search. The data returned looks like this:
"uniqueID=<ID>","<IP>","<hostname>",1
I save the results of the splunk report as $splunk, and then decalare array1 with the results of $splunk - the header information since the results come back in csv format
array1=( $(echo $splunk | sed 's/ /\n/g' | sed 1d) )
array2 is generated from a master file that I have stored locally. That contains all the application ID's in our ecosystem. For example
uid=<ID>
I cat the contents of the master file into array2
array2=( $(cat master.txt) )
I then want to find what IDs from array1 exsist in array2 and save that as array3. This requires some massaging of the data in array1 to make it match the format of array2.
oldIFS=$IFS IFS=$'\n\t'
array3=($(comm -12 <(echo "${array1[*]}" | sed 's/ /\n/g' | awk -F "\"," {'print $1'} | sed 's/\"//g' | sed 's/|/ /g' | awk -F$'=' -v OFS=$'=' '{ $1 = "uid" }1' | grep -i "OU=People" | sed 's/OU/ou/g' | sort) <(echo "${array2[*]}" | sort)))
IFS=$oldIFS
array 3 will then contain lines that match in both arrays
uid=<ID>
uid=<ID>
However I am looking for something more along the line of
"uid=<ID>","<IP>","<hostname>",1
"uid=<ID>","<IP>","<hostname>",1
I would do it like this:
join -t, \
<(printf '%s\n' "${Array1[#]}" | sort -t, -k1,1) \
<(printf '%s\n' "${Array2[#]}" | sort)
Use the join command with , as the field delimiter. The first "file" is the first array, one element per line, sorted on the first field (comma delimited); the second "file" is the second array, one element per line, sorted.
The output will be every line where the first element of the first file matches the element from the second file; for the example input it's
abc,123,hello
This makes only one assumption, namely that no array element contains a newline. To make it more robust (assuming GNU Coreutils), we can use NUL as the delimiter:
join -z -t, \
<(printf '%s\0' "${Array1[#]}" | sort -z -t, -k1,1) \
<(printf '%s\0' "${Array2[#]}" | sort -z)
This prints the output separated by NUL as well; to read the result into an array, we can use readarray:
readarray -d '' -t Array3 < <(
join -z -t, \
<(printf '%s\0' "${Array1[#]}" | sort -z -t, -k1,1) \
<(printf '%s\0' "${Array2[#]}" | sort -z)
)
readarray -d requires Bash 4.4 or newer. For older Bash, you can use a loop:
while IFS= read -r -d '' element; do
Array3+=("$element")
done < <(
join -z -t, \
<(printf '%s\0' "${Array1[#]}" | sort -z -t, -k1,1) \
<(printf '%s\0' "${Array2[#]}" | sort -z)
)
I don't know how to do this with comm, but I do have a solution for you with sed and grep. The following commands match on the regex uid=X,, where the string/array is in the form of uid=x or (uid=x uid=y) respectively.
# Array 2 (B) is a string
$ A=("uid=1,10.10.10.1,server1,1" "uid=2,10.10.10.2,server2,1")
$ B="uid=1"
$ echo ${A[#]} | grep -oE "([^ ]*${B},[^ ]*)"
uid=1,10.10.10.1,server1,1
# Array 2 (D) is an array
$ C=(${A[#]} "uid=3,10.10.10.3,server3,1" "uid=4,10.10.10.4,server4,1")
$ D=(${B} "uid=3")
$ echo ${C[*]} | grep -oE "([^ ]*($(echo ${D[#]} | sed 's/ /,|/g'))[^ ]*)"
uid=1,10.10.10.1,server1,1
uid=3,10.10.10.3,server3,1
# Content of arrays
$ echo ${A[#]}
uid=1,10.10.10.1,server1,1 uid=2,10.10.10.2,server2,1
$ echo ${B}
uid=1
$ echo ${C[#]}
uid=1,10.10.10.1,server1,1 uid=2,10.10.10.2,server2,1 uid=3,10.10.10.3,server3,1 uid=4,10.10.10.4,server4,1
$ echo ${D[#]}
uid=1 uid=3

create arrays from for loop output

I'm trying to understand what I'm doing wrong here, but can't seem to determine the cause. I would like to create a set of arrays from an output for a for loop in bash. Below is the code I have so far:
for i in `onedatastore list | grep pure02 | awk '{print $1}'`;
do
arr${i}=($(onedatastore show ${i} | sed 's/[A-Z]://' | cut -f2 -d\:)) ;
echo "Output of arr${i}: ${arr${i}[#]}" ;
done
The output for the condition is as such:
107
108
109
What I want to do is based on these unique IDs is create arrays:
arr107
arr108
arr109
The arrays will have data like such in each:
[oneadmin#opennebula/]$ arr107=($(onedatastore show 107 | sed 's/[A-Z]://' | cut -f2 -d\:))
[oneadmin#opennebula/]$ echo ${arr107[#]}
DATASTORE 107 INFORMATION 107 pure02_vm_datastore_1 oneadmin oneadmin 0 IMAGE vcenter vcenter /var/lib/one//datastores/107 FILE READY DATASTORE CAPACITY 60T 21.9T 38.1T - PERMISSIONS um- u-- --- DATASTORE TEMPLATE CLONE_TARGET="NONE" DISK_TYPE="FILE" DS_MAD="vcenter" LN_TARGET="NONE" RESTRICTED_DIRS="/" SAFE_DIRS="/var/tmp" TM_MAD="vcenter" VCENTER_CLUSTER="CLUSTER01" IMAGES
When I try this in the script section though I get output errors as such:
./test.sh: line 6: syntax error near unexpected token `$(onedatastore show ${i} | sed 's/[A-Z]://' | cut -f2 -d\:)'
I can't seem to figure out the syntax to use on this scenario.
In the end what I want to do is be able to compare different datastores and based on which on has more free space, deploy VMs to it.
Hope someone can help. Thanks
You can use the eval (potentially unsafe) and declare (safer) commands:
for i in $(onedatastore list | grep pure02 | awk '{print $1}');
do
declare "arr$i=($(onedatastore show ${i} | sed 's/[A-Z]://' | cut -f2 -d\:))"
eval echo 'Output of arr$i: ${arr'"$i"'[#]}'
done
readarray or mapfile, added in bash 4.0, will read directly into an array:
while IFS= read -r i <&3; do
readarray -t "arr$i" < <(onedatastore show "$i" | sed 's/[A-Z]://' | cut -f2 -d:)
done 3< <(onedatastore list | awk '/pure02/ {print $1}')
Better, back through bash 3.x, one can use read -a to read to an array:
shopt -s pipefail # cause pipelines to fail if any element does
while IFS= read -r i <&3; do
IFS=$'\n' read -r -d '' -a "arr$i" \
< <(onedatastore show "$i" | sed 's/[A-Z]://' | cut -f2 -d: && printf '\0')
done 3< <(onedatastore list | awk '/pure02/ {print $1}')
Alternately, one can use namevars to create an alias for an array with an arbitrarily-named array in bash 4.3:
while IFS= read -r i <&3; do
declare -a "arr$i"
declare -n arr="arr$i"
# this is buggy: expands globs, string-splits on all characters in IFS, etc
# ...but, well, it's what the OP is asking for...
arr=( $(onedatastore show "$i" | sed 's/[A-Z]://' | cut -f2 -d:) )
done 3< <(onedatastore list | awk '/pure02/ {print $1}')

Echo 2 Arrays Lists in Shell Script

I have a problem with array in bash. I wish to echo 2 Arrays in a list from the fist element from the convert array til the last element. The same thing for room_minute array.
#! /bin/bash
#! /usr/bin/perl
declare -a data;
declare -a convert;
declare -a sala_minutos;
data=($(./Minutes.php 2> /dev/null | grep -P -w -o [0-9]\{2\}\.[0-9]\{2\}\.[0-9]\{2\} | awk -v FS=/ -v OFS=/ '{print $2,$1,$3}'));
room_minutes=($(./Minutes.php 2> /dev/null | grep -oP '(?<=room: )[0-9]+'))
for ((i=0; i< ${#data[*]}; i++));
do
convert=($(date -d "${data[i]} 10:00:00" +%s));
done
echo ${convert[*]} ${room_minutes[*]}
Obs inside the arrays:
data = [09/03/16 09/01/16 09/02/16 09/03/16 09/04/16 09/05/16 09/06/16 09/07/16 09/08/16 09/09/16 09/10/16 09/11/16 09/12/16 09/13/16 08/25/16 08/26/16 08/27/16 08/28/16 08/29/16 08/30/16 08/31/16]
covert = [1472698800 1472785200 1472871600 1472958000 1473044400 1473130800 1473217200 1473303600 1473390000 1473476400 1473562800 1473649200 1473735600 1472094000 1472180400 1472266800 1472353200 1472439600 1472526000 1472612400]
room_minutes = [7339 8748 211 15 15927 7028 34 11112 12567 686 5 13988 11279 8465 4402 60 1 10380 8078 8422]
Thanks in Advance.
i think you want convert and room_minutes in two columns. i've changed as little as possible to accomplish this using multiline strings and paste instead of arrays. the data= and room_minutes= lines are unchanged except for stripping the outermost ()s.
#!/bin/bash
data=$(./Minutes.php 2> /dev/null | grep -P -w -o [0-9]\{2\}\.[0-9]\{2\}\.[0-9]\{2\} | awk -v FS=/ -v OFS=/ '{print $2,$1,$3}');
room_minutes=$(./Minutes.php 2> /dev/null | grep -oP '(?<=room: )[0-9]+');
convert=$(echo "$data" | xargs -I{} date -d "{} 10:00:00" +%s)
paste <(echo "$convert") <(echo "$room_minutes")
#!/bin/bash
data=($(./Minutes.php 2> /dev/null | grep -P -w -o [0-9]\{2\}\.[0-9]\{2\}\.[0-9]\{2\} | awk -v FS=/ -v OFS=/ '{print $2,$1,$3}'));
room_minutes=($(./Minutes.php 2> /dev/null | grep -oP '(?<=room: )[0-9]+'));
for ((i=0; i< ${#data[#]}; i++));
do
convert=($(date -d "${data[$i]} 10:00:00" +%s));
echo -e Room_Minutes ${convert[#]} ${room_minutes[$i]}
done

Shell script: Sed substitution throwing unknown command: ` '

I'm having some trouble getting around an issue related to performing a sed substitution with array's being passed into it as variables. I'm nearly certain it has something to do with the way I'm passing the variables, but I've been scouring for hours for a solution to no avail.
The arrays are initialized in the first six lines of code before attempting a sed substitution. The full script is below:
#!/bin/bash
scalarLineNums=( $(grep -nr 'MCSTEP\|NCSTEP\|ISAVE\|DCGRAX\|DCGRAY\|DCGRAZ\|DCSTEC\|DCTIME\|ICOUTF\|ICOUTI\|D1PEKS\|D1PEFR\|D1PEPF\|MBCON\|NBCON\|D1BNVX\|D1BNVY\|D1BNVZ\|I1BNVX\|I1BNVY\|I1BNVZ\|D1BNFX\|D1BNFY\|D1BNFZ\|D1BNAX\|D1BNAY\|D1BNAZ' Layer_Rough.Y3D | cut -d ":" -f 1) )
vectorLineNums=( $(sed -n -e '/D1BNVX\|D1BNVY\|D1BNVZ\|I1BNVX\|I1BNVY\|I1BNVZ\|D1BNFX\|D1BNFY\|D1BNFZ\|D1BNAX\|D1BNAY\|D1BNAZ/{n;=;p;}' Layer_Rough.Y3D | sed -n 1~2p) )
scalarValuesOriginal=( $(grep -nr 'MCSTEP\|NCSTEP\|ISAVE\|DCGRAX\|DCGRAY\|DCGRAZ\|DCSTEC\|DCTIME\|ICOUTF\|ICOUTI\|D1PEKS\|D1PEFR\|D1PEPF\|MBCON\|NBCON\|D1BNVX\|D1BNVY\|D1BNVZ\|I1BNVX\|I1BNVY\|I1BNVZ\|D1BNFX\|D1BNFY\|D1BNFZ\|D1BNAX\|D1BNAY\|D1BNAZ' Layer_Rough.Y3D | awk -F ' +' '{print $2}') )
vectorValuesOriginal=( $(sed -n -e '/D1BNVX\|D1BNVY\|D1BNVZ\|I1BNVX\|I1BNVY\|I1BNVZ\|D1BNFX\|D1BNFY\|D1BNFZ\|D1BNAX\|D1BNAY\|D1BNAZ/{n;=;p;}' Layer_Rough.Y3D | sed -n 2~2p) )
scalarValuesNew=( $(grep -nr 'MCSTEP\|NCSTEP\|ISAVE\|DCGRAX\|DCGRAY\|DCGRAZ\|DCSTEC\|DCTIME\|ICOUTF\|ICOUTI\|D1PEKS\|D1PEFR\|D1PEPF\|MBCON\|NBCON\|D1BNVX\|D1BNVY\|D1BNVZ\|I1BNVX\|I1BNVY\|I1BNVZ\|D1BNFX\|D1BNFY\|D1BNFZ\|D1BNAX\|D1BNAY\|D1BNAZ' new-variable-list.txt | awk -F ' +' '{print $2}') )
vectorValuesNew=( $(sed -n -e '/D1BNVX\|D1BNVY\|D1BNVZ\|I1BNVX\|I1BNVY\|I1BNVZ\|D1BNFX\|D1BNFY\|D1BNFZ\|D1BNAX\|D1BNAY\|D1BNAZ/{n;=;p;}' new-variable-list.txt | sed -n 2~2p) )
i=0
for linenumber in "${scalarLineNums[#]}"
do
sed -i "${linenumber}s/${scalarValuesOriginal[$i]}/${scalarValuesNew[$i]}/" Layer_Rough.Y3D
i=$((i+1))
done
The error I receive when trying to run the script is
sed: -e expression #1, char 2: unknown command: `
'
The for loop is an attempt to perform a substitution on a per line basis, i.e., sed 'line#s/oldvalue/newvalue/'. A few of the elements contain '+' and '-' characters as some of the values are stored in scientific notation, but do not contain any slashes or whitespace.

Looping an array index into a screen session [duplicate]

This question already has answers here:
Bash array as argument inside of screen
(2 answers)
Closed 8 years ago.
#!/bin/bash
IFS=$'\n'
fortune_lines=($(fortune | fold -w 30))
Screen_Session=$"{mainscreen}"
Screen_OneLiner=$(screen -p 0 -S ${Screen_Session} -X stuff "`printf "say ${fortune_lines[#]}\r"`")
for var in "${Screen_OneLiner[#]}"
do
echo -e "${var}"
done
The above script only prints out line 1 one of
IFS=$'\n'
fortune_lines=($(fortune | fold -w 30))
Instead of cycling through the whole index of "fortune_lines" Not sure how to make this work.
Any ideas?
FYI
I am only using
echo -e
to troubleshoot this script.
#!/bin/bash
#OLDIFS=$IFS
IFS=$'\r'
fortune_lines=($(cat /etc/passwd | fold -w 30))
#Screen_Session=$"{mainscreen}"
Screen_Session=`screen -ls|grep "\."|grep "("|awk '{print $1}'`
Screen_OneLiner=$(screen -p 0 -S ${Screen_Session} -X stuff "`printf "say ${fortune_lines[#]}\r"`")
#IFS=$OLDIFS;
for var in "${Screen_OneLiner[#]}"
do
echo -e "${var}"
done
works fine for me I changed IFS to \r and it pumped out /etc/passwd where as with \n it only printed 1st line

Resources