12

I would like to split a string into two halves and print them sequentially. For example:

abcdef

into

abc
def

Is there a simple way to do it, or it needs some string processing?

  • How do you have the incoming string? Variable? Stdin? Other? – Jeff Schaller May 30 at 21:24
  • 1
    In a variable. It doesn't really matter, as anything can be worked out (stdin input can be put in a variable). – Gabriel Diego May 30 at 21:27
  • It matters for efficiency, especially if it can be possibly-gigantic. And also for convenience. – Peter Cordes May 31 at 10:36
16

Using parameter expansion and shell arithmetic:

The first half of the variable will be:

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

The second half of the variable will be:

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

so you could use:

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

You could also use the following awk command:

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
  • Thanks for the response! – Gabriel Diego May 30 at 21:19
  • concise and elegant solution. – Dudi Boy May 30 at 21:32
  • 3
    You can get rid of the $((...)); the off and len part of the ${var:off:len} substitution are already evaluated as arithmetic expressions. Example: foo=01234567; echo "${foo:0:${#foo}/2} ${foo:${#foo}/2}". That's documented, and it's the same in zsh and ksh93 as in bash. – mosvy May 30 at 21:47
  • 3
    Note: If the length of the string is odd, this will still split it into two parts, but the second will be a character longer. – peterh May 31 at 7:39
8

Using split, here strings and command substitution:

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

Another awk script can be:

echo abcdef | awk '{print substr($0,1,length/2); print substr($0,length/2+1)}'
  • 1
    Note that it doesn't work with mawk or busybox awk because of the syntax ambiguity of division / and the /ERE/ operator, and the special case of () being optional for length (still those implementations are not POSIX compliant in that case). Using length() or length($0) here instead of length would help for those. You could also do awk 'BEGIN{half = int(length(ARGV[1]) / 2); print substr(ARGV[1], 1, half) ORS substr(ARGV[1], half+1)}' abcdef which would save the pipe and extra process and make it work even if the string contains newline characters. – Stéphane Chazelas May 31 at 10:55
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.

For example,

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

If the string length is not an even number, the second line will be longer. E.g.

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.