shockers script korn example bourne shell sh

shell - script - Iterando en dos listas en paralelo en/bin/sh



shell script example (9)

Esta debería ser una solución bastante limpia, pero a menos que use la bash de proceso de bash , requiere el uso de archivos temporales. No sé si eso es mejor o peor que invocar cut y sed sobre cada iteración.

#!/bin/sh list1="1 2 3" list2="a b c" echo $list1 | sed ''s/ //n/g'' > /tmp/a.$$ echo $list2 | sed ''s/ //n/g'' > /tmp/b.$$ paste /tmp/a.$$ /tmp/b.$$ | while read item1 item2; do echo $item1 - $item2 done rm /tmp/a.$$ rm /tmp/b.$$

Tengo dos listas de igual longitud, sin espacios en los elementos individuales:

list1="a b c" list2="1 2 3"

Quiero iterar sobre estas dos listas en paralelo, emparejando a con 1, b con 2, etc.

a 1 b 2 c 3

Estoy intentando admitir el moderno shell Bourne portátil, por lo que las matrices Bash / ksh no están disponibles. Desvanecerse a awk sería aceptable en un apuro, pero preferiría mantener esto en sh puro si es posible.

¡Gracias por cualquier sugerencia que pueda proporcionar!


Esto es un poco raro, pero hace el trabajo:

#!/bin/sh list1="1 2 3" list2="a b c" while [ -n "$list1" ] do head1=`echo "$list1" | cut -d '' '' -f 1` list1=`echo "$list1" | sed ''s/[^ ]* */(.*/)$//1/''` head2=`echo "$list2" | cut -d '' '' -f 1` list2=`echo "$list2" | sed ''s/[^ ]* */(.*/)$//1/''` echo $head1 $head2 done


NEVERMIND, VIENE "BOURNE" y pensó "BOURNE OTRA VEZ". Dejar esto aquí porque podría ser útil para alguien, pero claramente no es la respuesta a la pregunta, ¡lo siento!

-

Esto tiene algunas deficiencias (no maneja con gracia listas que son de diferentes tamaños), pero funciona para el ejemplo que usted dio:

#!/bin/bash list1="a b c" list2="1 2 3" c=0 for i in $list1 do l1[$c]=$i c=$(($c+1)) done c=0 for i in $list2 do echo ${l1[$c]} $i c=$(($c+1)) done

Hay formas más elegantes usando herramientas comunes de Unix como awk y cut, pero lo anterior es una implementación de pure-bash como se solicita

Comentando la respuesta aceptada, no funcionó para mí ni en Linux ni en Solaris, el problema era el atajo de clase de caracteres / S en la expresión regular para sed. Lo reemplacé con [^] y funcionó:

#!/bin/sh list1="1 2 3" list2="a b c" while [ -n "$list1" ] do head1=`echo "$list1" | cut -d '' '' -f 1` list1=`echo "$list1" | sed ''s/[^ ]* */(.*/)$//1/''` head2=`echo "$list2" | cut -d '' '' -f 1` list2=`echo "$list2" | sed ''s/[^ ]* */(.*/)$//1/''` echo $head1 $head2 done


Probablemente no sea portable (¡mire todos esos bash-ismos!), Pero es fácil de leer y alguien más puede encontrarle útil ...

list1="a b c" list2="1 2 3" array1=($list1) array2=($list2) count=${#array1[@]} for i in `seq 1 $count` do echo ${array1[$i-1]} ${array2[$i-1]} done


Solución que no usa matrices:

list1="aaa1 aaa2 aaa3" list2="bbb1 bbb2 bbb3" tmpfile1=$( mktemp /tmp/list.XXXXXXXXXX ) || exit 1 tmpfile2=$( mktemp /tmp/list.XXXXXXXXXX ) || exit 1 echo $list1 | tr '' '' ''/n'' > $tmpfile1 echo $list2 | tr '' '' ''/n'' > $tmpfile2 paste $tmpfile1 $tmpfile2 rm --force $tmpfile1 $tmpfile2


Estuve trabajando en una respuesta basada en sed cuando aparecieron las primeras soluciones aquí. Pero luego de una investigación más profunda, resultó que los elementos en la lista estaban separados por líneas nuevas, no espacios, lo que me permitió ir con una solución basada en la cabeza y la cola:

original_revs="$(cd original && git rev-parse --all)" && working_revs="$(cd working && git rev-parse --all)" && while test -n "$original_revs"; do original_commit="$(echo "$original_revs" | head -n 1)" && working_commit="$(echo "$working_revs" | head -n 1)" && original_revs="$(echo "$original_revs" | tail -n +2)" && working_revs="$(echo "$working_revs" | tail -n +2)" && ... done

Estoy publicando esto solo en caso de que alguien se encuentre con esta variante del problema, pero otorgo la respuesta aceptada basada en el problema tal como se publicó.


$ list1="1 2 3" $ list2="a b c" $ echo "$list1 $list2" | awk ''{n=NF/2; for (i=1;i<=n;i++) print $i,$(n+i) }'' 1 a 2 b 3 c


Esto debería ser portátil y también funciona con más de dos listas:

#!/bin/sh x="1 2 3 4 5" y="a b c d e" z="A B C D E" while read current_x x <<EOF $x EOF read current_y y <<EOF $y EOF read current_z z <<EOF $z EOF [ -n "$current_x" ] do echo "x=$current_x y=$current_y z=$current_z" done

El uso de parámeros posicionales también funciona. Tenga en cuenta que los elementos de la lista no pueden comenzar con "-". De lo contrario, "set" fallará.

#!/bin/sh x="1 2 3 4 5" y="a b c d e" z="A B C D E" while [ -n "$x" ] do set $x current_x=$1 shift x="$*" set $y current_y=$1 shift y="$*" set $z current_z=$1 shift z="$*" echo "x=$current_x y=$current_y z=$current_z" done


Como un trazador de líneas:

list2="1 2 3"; list1="a b c"; for i in $list1; do x=`expr index "$list2" " "`; [ $x -eq 0 ] && j=$list2 || j=${list2:0:$x}; list2=${list2:$x}; echo "$i $j"; done