Como dividir uma string em duas substrings do mesmo comprimento usando o bash?

12

Gostaria de dividir uma string em duas metades e imprimi-las sequencialmente. Por exemplo:

abcdef

para dentro

abc
def

Existe uma maneira simples de fazer isso ou precisa de algum processamento de string?

Gabriel Diego
fonte
Como você tem a string recebida? Variável? Stdin? De outros?
Jeff Schaller
1
Em uma variável. Realmente não importa, pois tudo pode ser resolvido (a entrada stdin pode ser colocada em uma variável).
Gabriel Diego
É importante para a eficiência, especialmente se puder ser possivelmente gigantesco. E também por conveniência.
Peter Cordes

Respostas:

16

Usando expansão de parâmetros e aritmética de shell :

A primeira metade da variável será:

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

A segunda metade da variável será:

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

então você pode usar:

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

Você também pode usar o seguinte 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
fonte
Obrigado pela resposta!
Gabriel Diego
solução concisa e elegante.
Dudi Boy
3
Você pode se livrar do $((...)); a parte offe lena ${var:off:len}substituição já são avaliadas como expressões aritméticas. Exemplo: foo=01234567; echo "${foo:0:${#foo}/2} ${foo:${#foo}/2}". Isso está documentado, e é o mesmo em zshe ksh93como em bash.
mosvy
3
Nota: Se o comprimento da string for ímpar, isso ainda será dividido em duas partes, mas a segunda será um caractere mais longo.
peterh - Restabelece Monica
8

Usando split, aqui strings e substituição de comando:

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

Outro awkscript pode ser:

echo abcdef | awk '{print substr($0,1,length/2); print substr($0,length/2+1)}'
Dudi Boy
fonte
1
Observe que ele não funciona com o mawk ou o busybox awk por causa da ambiguidade de sintaxe da divisão /e do /ERE/operador e pelo caso especial de ()ser opcional length(ainda essas implementações não são compatíveis com POSIX nesse caso). Usar length()ou length($0)aqui em vez de lengthajudaria para aqueles. Você também pode fazer o awk 'BEGIN{half = int(length(ARGV[1]) / 2); print substr(ARGV[1], 1, half) ORS substr(ARGV[1], half+1)}' abcdefque salvaria o pipe e o processo extra, além de fazê-lo funcionar, mesmo que a string contenha caracteres de nova linha.
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 exemplo,

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

Se o comprimento da string não for um número par, a segunda linha será mais longa. Por exemplo

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