Jak podzielić ciąg na dwa podciągi o tej samej długości za pomocą bash?


12

Chciałbym podzielić ciąg na dwie połówki i wydrukować je sekwencyjnie. Na przykład:

abcdef

w

abc
def

Czy istnieje prosty sposób, aby to zrobić, czy też wymaga przetworzenia ciągu?


Jak masz ciąg przychodzący? Zmienna? Stdin? Inny?
Jeff Schaller

1
W zmiennej. To naprawdę nie ma znaczenia, ponieważ wszystko można wypracować (wejście standardowe można umieścić w zmiennej).
Gabriel Diego

Ma to znaczenie dla wydajności, szczególnie jeśli może być gigantyczne. A także dla wygody.
Peter Cordes

Odpowiedzi:


16

Używanie rozszerzania parametrów i arytmetyki powłoki :

Pierwsza połowa zmiennej będzie:

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

Druga połowa zmiennej będzie:

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

więc możesz użyć:

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

Możesz także użyć następującego polecenia 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

Dzięki za odpowiedzi!
Gabriel Diego

zwięzłe i eleganckie rozwiązanie.
Dudi Boy

3
Możesz pozbyć się $((...)); offi lenczęść ${var:off:len}zastąpienia już ocenić jako wyrażeń arytmetycznych. Przykład: foo=01234567; echo "${foo:0:${#foo}/2} ${foo:${#foo}/2}". Który jest udokumentowany, a to samo w zshi ksh93jak w bashu.
mosvy

3
Uwaga: Jeśli długość łańcucha jest nieparzysta, nadal będzie on dzielony na dwie części, ale druga będzie dłuższa.
peterh - Przywróć Monikę

8

Używając splittutaj ciągów znaków i podstawiania poleceń:

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

7

Innym awkskryptem może być:

echo abcdef | awk '{print substr($0,1,length/2); print substr($0,length/2+1)}'

1
Zauważ, że nie działa z mawk lub busybox awk ze względu na dwuznaczność składni dzielenia /i /ERE/operatora oraz szczególny przypadek ()opcjonalności length(wciąż te implementacje nie są w tym przypadku zgodne z POSIX). Użycie length()lub length($0)tutaj zamiast lengthpomógłoby im. Możesz także zrobić to, awk 'BEGIN{half = int(length(ARGV[1]) / 2); print substr(ARGV[1], 1, half) ORS substr(ARGV[1], half+1)}' abcdefco oszczędziłoby potok i dodatkowy proces i sprawiłoby, że działało, nawet jeśli ciąg znaków zawiera znaki nowej linii.
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.

Na przykład,

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

Jeśli długość łańcucha nie jest liczbą parzystą, druga linia będzie dłuższa. Na przykład

$ echo abcdefg | python3 -c 's = input(); x= len(s) // 2; print(s[:x], s[x:], sep="\n")'
abc
defg
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.