Change the starter for loop index - shell

I want to compare two lists without recombination in shell script:
A=(a b c d e)
B=(b c d e f)
then print a combination
ab
ac
ad
ae
af
bc
bd
be
bf
...
de
df
ef
I am tried with 'for ' loop
------------------------CODE----------------------------------------
arr_a=(a b c d e f)
for i in 0 1 2 3 4
do
jdx=$(( $i + 1 ))
for j in {$jdx..5}
do
echo ${arr_a[$i]}'_'${arr_a[$j]}
done
done
--------------------END CODE ------------------------------------
But the problem is $jdx.
Any hints to solve this issue?

You can use brace expansion to do this:
$ A=(a b c d e)
$ B=(b c d e f)
$ eval echo $(echo {${A[#]}}{${B[#]}} | tr ' ' ',')
ab ac ad ae af bb bc bd be bf cb cc cd ce cf db dc dd de df eb ec ed ee ef
This is first outputting the arrays in the form {a,b,c,d,e}{b,c,d,e,f}, then brace expansion takes care of the rest.

Use C-style for loops:
for ((i=0; i < ${#A[#]}; i++)); do
for ((j=i; j < ${#B[#]}; j++)); do
echo ${A[i]}${B[j]}
done
echo
done
ab
ac
ad
ae
af
bc
bd
be
bf
cd
ce
cf
de
df
ef

Related

Using bash to get Two variables in for-loop form two different lists

I'm working with bash and I have two lists:
AZU SJI IOP
A1 B1 C1
Using the bash code below:
for f1 in AZU SJI IOP
do
for f2 in A1 B1 C1
do
echo $f1 + $f2
done
done
I get this result:
$ bash dir.sh
AZU + A1
AZU + B1
AZU + C1
SJI + A1
SJI + B1
SJI + C1
IOP + A1
IOP + B1
IOP + C1
I would like to get the result in this way
AZU A1
SJI B1
IOP C1
Define two arrays such that they have the same indices, then iterate over the indices of one array:
list1=(AZU SJI IOP)
list2=(A1 B1 C1)
for i in "${!list1[#]}"; do
echo "${list1[i]} ${list2[i]}"
done
You could of course use paste, but since your lists are not in files, you might be interested in a solution without external commands:
set -- A1 B1 C1
for f1 in AZU SJI IOP
do echo $f1 $1
shift
done

Converting string using bash

I want to convert the output of command:
dmidecode -s system-serial-number
which is a string looking like this:
VMware-56 4d ad 01 22 5a 73 c2-89 ce 3f d8 ba d6 e4 0c
to:
564dad01-225a-73c2-89ce-3fd8bad6e40c
I suspect I need to first of all extract all letters and numbers after the "VMware-" part at that start and then insert "-" at the known positions after character 10, 14, 18, 22.
To try the first extraction I have tried:
$ echo `dmidecode -s system-serial-number | grep -oE '(VMware-)?[a0-Z9]'`
VMware-5 6 4 d a d 0 1 2 2 5 a 7 3 c 2 8 9 c e 3 f d 8 b a d 6 e 4 0 c
However this isn't going the right way.
EDIT:
This gets me to a single log string however it's not elegant:
$ echo `dmidecode -s system-serial-number | sed -s "s/VMware-//" | sed -s "s/-//" | sed -s "s/ //g"`
564dad01225a73c289ce3fd8bad6e40c
Like this :
dmidecode -s system-serial-number |
sed -E 's/VMware-//;
s/ +//g;
s/(.)/\1-/8;
s/(.)/\1-/13;
s/(.)/\1-/23'
You can use Bash sub string extraction:
$ s="VMware-56 4d ad 01 22 5a 73 c2-89 ce 3f d8 ba d6 e4 0c"
$ s1=$(echo "${s:7}" | tr -d '[:space:]')
$ echo "${s1:0:8}-${s1:8:4}-${s1:12:9}-${s1:21}"
564dad01-225a-73c2-89ce-3fd8bad6e40c
Or, built-ins only (ie, no tr):
$ s1=${s:7}
$ s1="${s1// /}"
$ echo "${s1:0:8}-${s1:8:4}-${s1:12:9}-${s1:21}"

How a loop works in awk ? and do we get matched data from two files?

I am trying to extract data from two files with a common column but I am unable to fetch the required data.
File1
A B C D E F G
Dec 3 abc 10 2B 21 OK
Dec 1 %xyZ 09 3F 09 NOK
Dec 5 mnp 89 R5 11 OK
File2
H I J K
abc 10 6.3 A9
xyz 00 0.2 2F
pqr 45 6.9 3c
I am able to get output A B C D E F G but unable to add columns of File2 in between columns in File1 column.
Trail:
awk 'FNR==1{next}
NR==FNR{a[$1]=$2; next}
{k=$3; sub(/^\%/,"",k)} k in a{print $1,$2,$3,$a[2,3,4],$4,$5,$6,$7; delete a[k]}
END{for(k in a) print k,a[k] > "unmatched"}' File2 File1 > matched
Required output:
matched:
A B I C J K D E F G
Dec 3 10 abc 6.3 A9 10 2B 21 OK
Dec 1 00 %syz 0.2 2F 09 3F 09 NOK
unmatched :
H I J K
pqr 45 6.9 3c
Could you please help me for getting this output please ? Thank you.
awk '
FNR == 1 { next }
FNR==NR {
As[ $3] = $0
S3 = $3
gsub( /%/, "", S3)
ALs[ tolower( S3)] = $3
next
}
{
Bs[ tolower( $1)] = $0
}
END {
print "matched:"
print "A B I C J K D E F G"
for ( B in Bs){
if ( B in ALs){
split( As[ ALs[B]] " " Bs[B], Fs)
printf( "%s %s %s %s %s %s %s %s %s %s\n", Fs[1], Fs[2], Fs[9], Fs[3], Fs[10], Fs[11], Fs[4], Fs[5], F[6], F[7])
}
}
print "unmatched :"
print "H I J K"
for ( B in Bs) if ( ! ( B in ALs)) print Bs[ B]
}
' File1 File2
added non define constraint of ignore case of reference (%xyZ vs xyz)
need to keep both file in memory (array) to treat at the end. Matched could be done at reading. I keep, for understanding purpose output at END level
Your problem:
you mainly take reference to wrong file in your code (k=$3 is used when reading File2 with field from File1 reference, ...)

combine two variables in the same order in for loop unix

It sounds simple but I can't do it in a simple way. In shell for loop, two vars
A=" 1 2 3 4"
B=" a b c d"
, try to print 1a 2b 3c 4d. Tried
A=" 1 2 3 4"
B=" a b c d"
for m in $A
for n in $B;
do echo $m$n done.
The output is
1
2
3
4
5
for
l
in
a
b
c
d
e
Anyone can help this out?
Here's one way to do it:
$ A=(1 2 3 4); B=(a b c d); for i in $(seq 0 3); do echo ${A[$i]}${B[$i]}; done
1a
2b
3c
4d
In your attempt, the for cases aren't closed with a ;, so it keeps interpreting words in your second for statement as cases for the first for statement.
Use instead:
A="1 2 3 4"
B="a b c d"
for m in $A ; do
for n in $B ; do
echo $m$n
done
done

Why did my alphabet had 40 letters? Or why dropping STDERR is not always a good idea [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
for ((i=000;i<040;i++));do ...
From 0 to 39, there is 40 values!? ... for printing from A to Z???
for ((i=000;i<040;i++));do
echo -e $(eval "printf "\\\\%04o" $((65+0$i)) ");
done 2>/dev/null |
xargs
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
strange!?
There is 85 values, from 70 to 154:
for ((i=0070;i<0155;i++));do
echo -e $(eval "printf "\\\\%04o" $((19+0$i)) ");
done 2>/dev/null |
xargs
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
Complete answer wanted, explaining 𝒂𝒍𝒍 missing values.
:-p
My full answer
As this question was closed, no answer could be added, so there is my explanation:
The missunderstanding is done by the (ab)use of 2>/dev/null!!
So, simply dropping this will output:
for ((i=000;i<040;i++));do
echo -e $(eval "printf "\\\\%04o" $((65+0$i)) ")
done | xargs
bash: 65+08: value too great for base (error token is "08")
bash: 65+09: value too great for base (error token is "09")
bash: 65+018: value too great for base (error token is "018")
bash: 65+019: value too great for base (error token is "019")
bash: 65+028: value too great for base (error token is "028")
bash: 65+029: value too great for base (error token is "029")
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
Things become more clear!
for ((i=000;i<040;i++));do
echo -e $(eval "printf "\\\\%04o" $((65+0$i)) ")
done 2> >(wc -l >&2) | xargs
6
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
There are 6 error lines, because of illegal 8 or 9 digit in octal numbers.
So if this is octal, then you could either
printf %d\\n 040
or
echo $(( 040 ))
to convert 040 octal to 32 decimal. Then 32 operation with 6 errors, there are really 26 outputs.
for ((i=0070;i<0155;i++));do
echo -e $(eval "printf "\\\\%04o" $((19+0$i)) ")
done 2> >(wc -l >&2) | xargs
27
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
There is in fact 27 errors, with values from... 56 to 108:
printf "%d\n" 0070 0155
56
109
There is not 85 values, but 53:
echo $(( 155 - 70 )) $(( 0155 - 0070 )) $(( 109 - 56 ))
85 53 53
Again: 53 operations with 27 errors = 26 outputs
echo $((53-27))
26
Yes!
This is the right number of letters (in my alphabet)!
Conclusion
The question could be rewritten as:
How abuse of /dev/null could make strange behaviours
So be carefull when redirecting STDERR! Avoid simply redirecting STDERR to /dev/null:
command 2>/dev/null
And prefer to use commands like:
command 2> >(grep -v "unwanted message" >&2)
You have 31 steps because 040 is octal for decimal 32.
Octal is a numeral system with the base 8. Decimal has the base 10 and hexadecimal 16.
You are simply using octal numbers, as your numbers are prefixed by 0.
So it's base 8, not base 10.
Why don't you just use the following to print the alphabet?
for letter in {A..Z} ; do
echo $letter
done

Resources