Bash while read input issue - bash

An possible way to use while read is:
while read server application date; do ..
So now i could print only the applications, i understand that. So here comes my question:
with my example i know exactly how many "arrays" there are but how would i do it if i dont know how many "arrays" exist per line?
Example file:
Server : ID1 ; ID2 ; ID3
Server : ID1
Server : ID1 ; ID2
Server : ID1 ; ID2 ; ID3 ; ID4
It doesnt have to be with read but how could i read them so i could for example
echo "$Server $ID3"
p.s sorry for the bad english
so what i am doing so far is this:
#!/bin/bash
file=$1
csv=$2
echo Server : Applikation : AO : BV : SO > endlist.txt
while read server aid; do
grep $aid $csv | while IFS=";" read id aid2 name alia status typ beschreibung gesch gesch2 finanzierung internet service servicemodell AO BV SO it betrieb hersteller; do
if [[ $aid == $aid2 ]]
then
echo $server : $name : $AO : $BV : $SO >> endlist.txt
fi
done
done < $file
the Problem is that the first while read is for now only SERVER and AID but i want to edit this file so more than one AID is possible

It doesnt have to be with read but how could i read them so i could for example
echo "$Server $ID3"
First split the input on :, then read the array on ;. Use bash arrays and read -a to save input to an array.
# split the input on `:` and spaces
while IFS=' :' read -r server temp_ids; do
# split the ids on `;` and spaces into an array
IFS=' ;' read -r -a id <<<"$temp_ids"
# check if there are at least 3 elements
if ((${#id[#]} >= 3)); then
# array numbering starts from 0
echo "$server ${id[2]}"
else
echo There is no 3rd element...
fi
done <<EOF
Server : ID1 ; ID2 ; ID3
Server : ID1
Server : ID1 ; ID2
Server : ID1 ; ID2 ; ID3 ; ID4
EOF
will output:
Server ID3
There is no 3rd element...
There is no 3rd element...
Server ID3

Related

UNIX Pattern Sequence

The following scenario is for pattern search using UNIX Shell where the pattern between two strings need to happen and then a new column with sequence need to happen
Input Data
1|AB|1|2
2|BC|1|2
ID CLOSED
3|AB|1|2
4|BC|1|2
ID CLOSED
Query
As per the data above, we need to add SEQ column after UN and it should add
seq 1 as the first value and sequence 2 to the second part and so on till End.
Expected Output
1|AB|1|2|1
2|BC|1|2|1
3|AB|1|2|2
4|BC|1|2|2
Tried solution as first part but isn't giving correct output
sed -n '/^ID/,/^ID CLOSED/{p;/^pattern2/q}'
Any particular reason you want to use sed for this? It seems like a better fit for awk:
awk -v{,O}FS='|' '
BEGIN { seq = 1 }
/CLOSED/ { seq++ }
!/^ID/ { $5=seq; print }'
Output:
1|AB|1|2|1
2|BC|1|2|1
3|AB|1|2|2
4|BC|1|2|2
Maybe something like this:
(
seq=1
echo "ID NAME ID1 ID2 ID3 UN SEQ"
while read id name id1 id2 id3 un; do
[ "$id $name" = "ID NAME" ] && continue
[ "$id $name" = "ID CLOSED" ] && { let "seq+=1"; continue; }
echo "$id $name $id1 $id2 $id3 $un $seq"
done < /path/to/the/datafile
echo "ID CLOSED"
) | column -t -s' '
Doing this with just a sed instruction is not impossible I think, but a way much harder ;)

Bash: rename duplicates for generated values in csv file

There is a bash script that create a email addresses in next format: first letter from name and full surname, lowercase +#example.com.
csv file:
id,location,name,email
1,1,John Smith,ab#dc.com
2,2,Paul Robinson,
3,3,Fidel Guererro,qw#er.com
4,4,John Smith,
...
Column Name can contain duplicates. In this case script should add 1 in email address (ex. for id=1 - jsmith#example.com, for id=4 - jsmith1#example.com).
I try next script:
#!/bin/bash
while IFS=, read -r col1 col2 col3 col4
do
if [ "$col1" == Id ]; then
echo "${col1},${col2},${col3},${col4}"
continue
fi
firstinitial=${col3:0:1}
surname=$(echo $col3 | cut -d' ' -f2)
if [[ $col4 == $col4 ]]; then
col4=${firstinitial,}${surname,,}1#example.com
else
col4=${firstinitial,}${surname,,}#example.com
fi
echo "${col1},${col2},${col3},${col4}"
done < acc.csv
I recieve all addresses with 1.
How can I change this script?
Expected output:
id,location,name,email
1,1,John Smith,jsmith#example.com
2,2,Paul Robinson,probinson#example.com
3,3,Fidel Guererro,fguererro#example.com
4,4,John Smith,jsmith1#example.com
...

change charters in a string based on vcf table data

I have a long string file (string.txt) (abcdefghijklmnop)
and a vcf table (file.vcf) which lools like that
position 2 4 6 10 n...
name1 a b c d
name2 x y z a
namen...
the table also contain "mis" and "het" and in this case the character should not be replaced
I want to change the characters in the specific location and store all the strings in a new file that will look like this
>name1
aacbecghidklmnop
>name2
axcyezghiaklmnop
is there a way to do it in a bash loop ?
Would you please try the following:
mapfile -t string < <(fold -w1 "string.txt")
# set string to an array of single characters: ("a" "b" "c" "d" ..)
while read -ra ary; do
if [[ ${ary[0]} = "position" ]]; then
# 1st line of file.vcf
declare -a pos=("${ary[#]:1}")
# now the array pos holds: (2 4 6 10 ..)
else
# 2nd line of file.vcf and after
declare -a new=("${string[#]}")
# make a copy of string to modify
for ((i=0; i<${#pos[#]}; i++ )); do
repl="${ary[$i+1]}" # replacement
if [[ $repl != "mis" && $repl != "het" ]]; then
new[${pos[$i]}-1]="$repl"
# modify the position with the replacement
fi
done
echo ">${ary[0]}"
(IFS=""; echo "${new[*]}")
# print the modified array as a concatenated string
fi
done < "file.vcf"
string.txt:
abcdefghijklmnop
file.vcf:
position 2 4 6 10
name1 a b c d
name2 x y z a
name3 i mis k l
Output:
>name1
aacbecghidklmnop
>name2
axcyezghiaklmnop
>name3
aicdekghilklmnop
I have tried to embed explanations as comments in the script above, but
if you still have a question, please feel free to ask.
Hope this helps.

how to merge two data based on one

I have two data saved at .txt in a folder
data1 which is called data 1 includes of one column data as follows
from
A0A0A6YXQ7
A0A0A6YXS5
A0A0A6YXW8
A0A0A6YXX6
A0A0A6YXZ1
A0A0A6YY28
A0A0A6YY43
A0A0A6YY47
A0A0A6YY78
A0A0A6YY89
A0A0A6YY91
A0A0A7NQN9
and the second data has two columns fromand to
from to
A0A0A6YXQ7 Myo1f
A0A0A6YXW8 Pak2
A0A0A6YXX6 Arhgap15
A0A0A6YXZ1 Igtp
A0A0A6YY28 pol
A0A0A6YY47 MumuTL
A0A0A6YY78 MumuTL
A0A0A6YY78 MumuTLM
A0A0A6YY91 MumuTL
A0A0A6YY91 MumuTLM
data1 and data2 have a column named from
all strings in data1 should be in data2. if they are not.
I want to load the two data, and if the any string does not exist in the data2, I want to put it there as data1
for example, in data2 the following strings are missing
A0A0A6YXS5 and A0A0A6YY43 and A0A0A6YY89 and A0A0A7NQN9
so the output will look like this
From To
A0A0A6YXQ7 Myo1f
A0A0A6YXS5 -
A0A0A6YXW8 Pak2
A0A0A6YXX6 Arhgap15
A0A0A6YXZ1 Igtp
A0A0A6YY28 pol
A0A0A6YY43 -
A0A0A6YY47 MumuTL
A0A0A6YY78 MumuTL;MumuTLM
A0A0A6YY89 -
A0A0A6YY91 MumuTL;MumuTLM
A0A0A7NQN9 -
How about:
#!/bin/bash
declare -A hash
# scan in file2 and make a key-value(s) table
while read line; do
set -- $line
if [ -z ${hash[$1]} ]; then
hash[$1]=$2
else
hash[$1]="${hash[$1]};$2"
fi
done < data2
# read file1 as keys and print appropriate value(s)
while read line; do
if [ -z ${hash[$line]} ]; then
echo $line "-"
else
echo $line ${hash[$line]}
fi
done < data1
Note that "from" and "to" pair are accidentally properly processed.
Hope this helps.

Matching matrix in perl or bash

I was wondering if you could give me a hand to find a solution (not necesseraly giving me a code) to my problem.
I would like to create a "matching matrix" in perl or Bash.
Basically, my first file is an extracted list of IDs, not unique (file1)
ID1
ID4
ID20
ID1
For making my life easier my second file is just a long line with multiples IDs (file2)
ID1 ID2 ID3 ID4 .... IDn
I would like to achieve this output:
ID1 ID2 ID3 ID4 ID5 ID6 ID7 .... ID20 IDn
ID1 X
ID4 X
ID20 X
ID1 X
The tricky part for me is to add the "X" when a match is found.
Any help, hint is more than appreciated.
Here's my answer for this issue:
use warnings;
use strict;
open(FILE1, "file1") || die "cannot find file1";
open(FILE2, "file2") || die "cannot find file2";
#read file2 to create hash
my $file2 = <FILE2>;
$file2 =~ s/\n//;
my #ids = split(/\s+/, $file2);
my %hash;
my $i = 1;
map {$hash{$_} = $i++;} #ids;
#print the first line
printf "%6s",'';
for my $id (#ids) {
printf "%6s", $id;
}
print "\n";
#print the other lines
while(<FILE1>) {
chomp;
my $id = $_;
printf "%6s", $id;
my $index = $hash{$id};
if ($index) {
$index = 6 * $index;
printf "%${index}s\n",'x';
} else {
print "\n";
}
}

Resources