Alternate merge strings in BASH

Tag: string , bash , shell , scripting Author: ice6267907 Date: 2013-03-20

From

KS=$(locate acpi-support | grep "/etc/rc" | cut -f4 -d/ | tr -dc '[K,S]')
LEVELS=$(locate acpi-support | grep "/etc/rc" | cut -f3 -d/ | tr -dc '[0-9]')
echo $KS
echo $LEVELS

I get the following outputs:

KSSSS
12345

What I'd like to do is to merge alternatively the previous outputs in this way:

K1 S2 S3 S4 S5

I tried whit nested for loops but without success, how could I do it?

Other Answer1

You can use a for loop to iterate over the characters in one of the strings and then use bash's substring functionality to print out characters. This is shown below:

KS="KSSSS"
LEVELS="12345"
unset result
for (( i=0; i<${#KS}; i++ )); do
  result+="${KS:$i:1}${LEVELS:$i:1} "
done
echo "$result"

Output:

K1 S2 S3 S4 S5

comments:

I like the way it is more general ${#KS} and the result+= issue, to make it more general than mine. +1

Other Answer2

$ KS=KSSSS

$ LEVELS=12345

$ awk '{n=length/2;for(i=1;i<=n;i++)print $i$(i+n)}' ORS=" " FS= <<< "$KS$LEVELS"
K1 S2 S3 S4 S5

comments:

+1. I knew an awk one-liner will arrive.
What a powerful tool! Thanks :)
@fedorqui I wasn't going to but I saw your comment. I know there is a more elegant solution for this, it will come to me!

Other Answer3

Python one-liner

$ KS="KSSSS"
$ LEVELS="12345"
$ python -c 'import sys; print " ".join([k+v for k,v in zip(sys.argv[1], sys.argv[2])])' $KS $LEVELS
K1 S2 S3 S4 S5
$

Other Answer4

This should work:

KS="KSSSS"
LEVELS="12345"
for i in {0..4}; do
  echo ${KS:$i:1}${LEVELS:$i:1}
done

Although for sure awk guru will come to rescue with better one-liner way : )

To make it appear all on the same line:

for i in {0..4}; do
  echo ${KS:$i:1}${LEVELS:$i:1} | awk '{printf("%s ",$1)}
done

comments:

Thanks in advance, but I think that's not a generic way to get my goal; on an other try I get SKSKK and 0245, the for you suggested me should be modified, since I may not always have a complete range from 1 to 5 :) I'll take a look to awk!
@dogbane generalized it. Having a for (( i=0; i<${#KS}; i++ )); loop, which I think it's better. Did not update my answer not to copy.

Other Answer5

If you make KS and LEVELS arrays instead of strings, you can use paste:

KS=( $(locate acpi-support | grep "/etc/rc" | cut -f4 -d/ | tr -dc '[K,S]') )
LEVELS=( $(locate acpi-support | grep "/etc/rc" | cut -f3 -d/ | tr -dc '[0-9]') )

paste -d"\0" <( printf "%s\n" ${KS[@]}) <( printf "%s\n" ${LEVELS[@]})