¿Cómo dividir una cadena en dos subcadenas de la misma longitud usando bash?

12

Me gustaría dividir una cadena en dos mitades e imprimirlas secuencialmente. Por ejemplo:

abcdef

dentro

abc
def

¿Hay una manera simple de hacerlo o necesita un procesamiento de cadena?

Gabriel Diego
fuente
¿Cómo tienes la cadena entrante? ¿Variable? Stdin? ¿Otro?
Jeff Schaller
1
En una variable Realmente no importa, ya que todo se puede resolver (la entrada estándar se puede poner en una variable).
Gabriel Diego
Es importante para la eficiencia, especialmente si puede ser posiblemente gigantesco. Y también por conveniencia.
Peter Cordes

Respuestas:

16

Usando la expansión de parámetros y la aritmética de shell :

La primera mitad de la variable será:

${var:0:${#var}/2}

La segunda mitad de la variable será:

${var:${#var}/2}

para que puedas usar:

printf '%s\n' "${var:0:${#var}/2}" "${var:${#var}/2}"

También puede usar el siguiente comando awk:

awk 'BEGIN{FS=""}{for(i=1;i<=NF/2;i++)printf $i}{printf "\n"}{for(i=NF/2+1;i<=NF;i++){printf $i}{printf "\n"}}'

$ echo abcdef | awk 'BEGIN{FS=""}{for(i=1;i<=NF/2;i++)printf $i}{printf "\n"}{for(i=NF/2+1;i<=NF;i++){printf $i}{printf "\n"}}'
abc
def
jesse_b
fuente
¡Gracias por la respuesta!
Gabriel Diego
Solución concisa y elegante.
Dudi Boy
3
Puedes deshacerte de la $((...)); La parte offy lenla ${var:off:len}sustitución ya se evalúan como expresiones aritméticas. Ejemplo: foo=01234567; echo "${foo:0:${#foo}/2} ${foo:${#foo}/2}". Eso está documentado, y es lo mismo en zshy ksh93como en bash.
mosvy
3
Nota: Si la longitud de la cadena es impar, esto aún la dividirá en dos partes, pero la segunda será un carácter más largo.
peterh - Restablece a Monica
8

Usando split, aquí cadenas y sustitución de comandos:

var=abcdef
printf '%s\n' "$(split -n1/2 <<<$var)" "$(split -n2/2 <<<$var)"
Freddy
fuente
7

Otro awkscript puede ser:

echo abcdef | awk '{print substr($0,1,length/2); print substr($0,length/2+1)}'
Dudi Boy
fuente
1
Tenga en cuenta que no funciona con mawk u busybox awk debido a la ambigüedad de sintaxis de la división /y el /ERE/operador, y el caso especial de ()ser opcional para length(aún esas implementaciones no son compatibles con POSIX en ese caso). Usar length()o length($0)aquí en lugar de lengthayudaría a aquellos. También podría hacer awk 'BEGIN{half = int(length(ARGV[1]) / 2); print substr(ARGV[1], 1, half) ORS substr(ARGV[1], half+1)}' abcdeflo que ahorraría la tubería y el proceso adicional y lo haría funcionar incluso si la cadena contiene caracteres de nueva línea.
Stéphane Chazelas
1

Python 3

s = input()  # Take one line of input from stdin.
x = len(s) // 2  # Get middle of string. "//" is floor division
print(s[:x], s[x:], sep="\n")  # Print "s" up to "x", then "s" past "x", joined on newlines.

Por ejemplo,

$ echo abcdef | python3 -c 's = input(); x = len(s) // 2; print(s[:x], s[x:], sep="\n")'
abc
def

Si la longitud de la cadena no es un número par, la segunda línea será más larga. P.ej

$ echo abcdefg | python3 -c 's = input(); x= len(s) // 2; print(s[:x], s[x:], sep="\n")'
abc
defg
wjandrea
fuente