Wie füge ich alle vier Zeichen ein Leerzeichen in eine lange Zeile ein?

30

Ich habe eine lange Zeile, in die ich alle 4 Zeichen ein Leerzeichen einfügen möchte, um das Lesen zu vereinfachen. Wie geht das am einfachsten? auch sollte ich in der Lage sein, die Linie von einem Rohr einzugeben. z.B

echo "foobarbazblargblurg" | <some command here>

gibt

foob arba zbla rgbl urg
Xenoterracid
quelle

Antworten:

54

Verwenden Sie sed wie folgt:

$ echo "foobarbazblargblurg" | sed 's/.\{4\}/& /g'
foob arba zbla rgbl urg
Dogbane
quelle
1
sedIch fluchte , das war so nah an dem, was ich zuerst versucht hatte, dass ich mich selbst treten konnte.
Xenoterracide
7
Nur neugierig, was das '&' leistet? Oh, es steht für "das, was gerade gepasst hat". Wie dumm von mir.
Omnifarious
1
es sollte beachtet werden, dass dies auch ein Leerzeichen am Ende hinzufügt, wenn die Zeichenfolge ein weiteres Zeichen enthält, was möglicherweise nicht wünschenswert ist
Anubis
@ Anubis's/.\{4\}/& /g;s/ $//'
wieczorek1990
20

Sie können das folgende einfache Beispiel verwenden:

$ echo "foobarbazblargblurg" | fold -w4 | paste -sd' ' -
foob arba zbla rgbl
Kenorb
quelle
Sehr schön ... Ich denke, das ist noch besser als die sedAntwort. Ich wusste es foldvorher nicht.
Wildcard
1
Leider foldfunktioniert es mit aktuellen GNU-Versionen nicht mit Mehrbyte-Zeichen (wie echo €€€€€€€€ | fold -w4 | paste -sd' ' -in UTF-8).
Stéphane Chazelas
3

Hier ist das Beispiel mit grepund xargs:

$ echo "foobarbazblargblurg" | grep -o .... | xargs
foob arba zbla rgbl
Kenorb
quelle
xargsLäuft echostandardmäßig, daher funktioniert es -nenje nach echoImplementierung nicht mit Wörtern wie oder mit Backslashes . Ab und zu wird auch ein ungerades Zeilenumbruchzeichen angezeigt, wenn xargs mehr als eins ausführt echo. Besser zum Pfeifen paste -sd ' ' -. Beachten Sie, dass dies -okeine Standardoption ist.
Stéphane Chazelas
3

Nur in Bash, keine externen Befehle:

str="foobarbazblargblurg"
[[ $str =~ ${str//?/(.)} ]]
printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"

oder als Einleitungsversion:

echo foobarbazblargblurg | 
  { IFS= read -r str; [[ $str =~ ${str//?/(.)} ]]; \
    printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"; }

Dies funktioniert, indem jedes Zeichen der Zeichenfolge in ein "(.)" Konvertiert wird, um eine Übereinstimmung mit =~dem regulären Ausdruck und eine Erfassung mit ihm zu erzielen. Anschließend werden nur die erfassten Ausdrücke aus dem BASH_REMATCH[]Array ausgegeben , die nach Bedarf gruppiert sind. Führende / nachfolgende / Zwischenräume bleiben erhalten, entfernen Sie die Anführungszeichen, um "${BASH_REMATCH[@]:1}"sie wegzulassen.

Hier ist es in eine Funktion eingeschlossen, diese verarbeitet ihre Argumente oder liest stdin, wenn es keine Argumente gibt:

function fmt4() {
  while IFS= read -r str; do
    [[ $str =~ ${str//?/(.)} ]]
    printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"
  done < <( (( $# )) && printf '%s\n' "$@" || printf '%s\n' $(< /dev/stdin) )
}

$ echo foobarbazblargblurg | fmt4
foob arba zbla rgbl urg 

Sie können die Anzahl einfach parametrisieren, um die Formatzeichenfolge entsprechend anzupassen.

Ein abschließendes Leerzeichen wird hinzugefügt. Verwenden Sie zwei printfanstelle von einem, wenn dies ein Problem ist:

printf "%s%s%s%s" "${BASH_REMATCH[@]:1:4}"
(( ${#BASH_REMATCH[@]} > 5 )) && printf " %s%s%s%s" "${BASH_REMATCH[@]:5}"

Der erste printfdruckt (bis zu) die ersten 4 Zeichen, der zweite druckt bedingt den gesamten Rest (falls vorhanden) mit einem führenden Leerzeichen, um die Gruppen zu trennen. Der Test ist für 5 Elemente, nicht für 4, um das nullte Element zu berücksichtigen.

Anmerkungen:

  • Shell printf‚s %cstatt verwendet werden könnte %s, %c(vielleicht) macht die Absicht klarer, aber es ist nicht Mehrbytezeichensatz sicher. Wenn Ihre Version von bash in der Lage ist, sind alle oben genannten Zeichen mehrbyte-sicher.
  • Shell verwendet die printfFormatzeichenfolge so lange, bis die Argumente aufgebraucht sind. Daher werden nur 4 Argumente gleichzeitig verschlungen und die nachfolgenden Argumente verarbeitet.
  • BASH_REMATCH[0] ist die gesamte übereinstimmende Zeichenfolge, daher wird nur ab Index 1 ausgegeben
  • Verwenden Sie printf -v myvar ...stattdessen, um in einer Variablen zu speichern myvar(vorbehaltlich des üblichen Leseschleifen- / Subshell-Verhaltens).
  • printf "\n"bei Bedarf hinzufügen

Sie können das oben beschriebene Ergebnis erzielen, indem zshSie das Array match[]anstelle von verwenden BASH_REMATCH[]und 1 von allen Indizes subtrahieren, da zshkein 0-Element für die gesamte Übereinstimmung beibehalten wird.

mr.spuratic
quelle
3

Mit zshnur:

str=foobarbazblargblurg

set -o extendedglob
printf '%s\n' ${str//(#m)????/$MATCH }

Oder

printf '%s%s%s%s ' ${(s::)str}

mit ksh93nur:

printf '%s\n' "${str//????/\0 }"

Nur mit einer POSIX-Shell (auch das nachfolgende Leerzeichen vermeiden, wenn die Eingabelänge ein Vielfaches von 4 ist):

out=
while true; do
  case $str in
    (?????*)
      new_str=${str#????}
      out=$out${str%"$new_str"}' '
      str=$new_str
      ;;
    (*)
      out=$out$str
      break
  esac
done
printf '%s\n' "$out"

Nun, das ist für Charaktere . Wenn Sie es auf Graphem-Clustern machen möchten (zum Beispiel, um zu brechen Stéphane, geschrieben als $'Ste\u0301phane', als Stép haneund nicht Ste phan e), mit zsh:

set -o rematchpcre
str=$'Ste\u301phane' out=
while [[ $str =~ '(\X{4})(.+)' ]] {
  out+="$match[1] " str=$match[2]
}
out+=$str
printf '%s\n' $out

Mit ksh93 könnten Sie auch nach der Anzeigebreite aufteilen, was für die Stéphaneoben genannten Fälle hilfreich wäre , aber auch, wenn andere Arten von Zeichen mit null oder doppelter Breite betroffen sind:

str=$'Ste\u301phane' out=
while
  start=${ printf %L.4s. "$str"; }
  start=${start%.}
  [ "$start" != "$str" ]
do
  out+="$start " str=${str#"$start"}
done
out+=$str
printf '%s\n' "$out"
Stéphane Chazelas
quelle
2

Ich werde nur die erforderlichen Leerzeichen einfügen, damit mindestens alle 4 Zeichen in einer Zeile ein Leerzeichen erscheint. Ich bin mir nicht sicher, wie ich mit diesem Fall umgehen soll. Wenn Sie beispielsweise "aa bbccdd" eingeben, erhalten Sie die Ausgabe "aa bbcc dd" und nicht "aa b bccd d".

Ich verwende Perl für Lookahead, bin aber mit Perl im Allgemeinen nicht sehr vertraut, daher sind möglicherweise Optimierungen erforderlich:

$ echo "foobarbazblargblurg" | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g'
foob arba zbla rgbl urg

$ echo 'aa bbccdd' | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g'
aa bbcc dd
# not 'aa b bccd d'!

$ echo 'some input' | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g'
some inpu t
# not 'some  inp ut'!

$ echo $'aabb\nc cddee' | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g' | 
> while read; do echo "${REPLY}x"; done
aabbx
c cdde ex
# no spaces added at the end of the first line (while loop to add to the end of
# the line and show this)
Fred Nurk
quelle
0

Ich habe dies mit Python gemacht

Zuerst lese ich eine Datei, dann teile ich durch 4 Zeichen und füge Leerzeichen hinzu

#!/usr/bin/python
import re
b=re.compile(r'[a-z]{4}')

p=open('/root/l.txt','r')
i=p.readlines()
for j in i:
    m=re.findall(b,j)
print " " .join (m) + "  "

/root/l.txt ==> Besteht aus dem Inhalt, den Sie im Beispiel angegeben haben

Ausgabe

foob arba zbla rgbl
Praveen Kumar BS
quelle