Antworten:
Mit sed
:
$ echo "123456789" | sed 's/\([[:digit:]]\{3\}\)\([[:digit:]]\{3\}\)\([[:digit:]]\{3\}\)/\1,\2,\3/g'
123,456,789
(Beachten Sie, dass dies nur für genau 9 Stellen funktioniert!)
oder dies mit sed
:
$ echo "123456789" | sed ':a;s/\B[0-9]\{3\}\>/,&/;ta'
123,456,789
Mit printf
:
$ LC_NUMERIC=en_US printf "%'.f\n" 123456789
123,456,789
echo 123456789 | awk '$0=gensub(/(...)/,"\\1,","g"){sub(",$",""); print}'
sed
funktioniert erstens nur, wenn die Nummer genau 9 Stellen hat. Das printf
funktioniert nicht auf zsh. Somit ist die zweite sed
Antwort wahrscheinlich die beste.
echo 123456789 | awk '{printf ("%'\''d\n", $0)}'
(was offensichtlich nicht immer unter Linux funktioniert!?, Aber unter AIX und Solaris funktioniert es einwandfrei)
bash
‚s printf
unterstützt so ziemlich alles , was Sie können in der tun printf
C - Funktion
type printf # => printf is a shell builtin
printf "%'d" 123456 # => 123,456
printf
von Coreutils wird das gleiche tun
/usr/bin/printf "%'d" 1234567 # => 1,234,567
vsnprintf
. Auf einem GNU / Linux-System scheint glibc es seit mindestens 1995 unterstützt zu haben.
export LC_NUMERIC="en_US"
wenn Sie Kommas erzwingen möchten.
locale -a
. Ich mussteen_US.utf8
Sie können numfmt verwenden:
$ numfmt --grouping 123456789
123,456,789
Oder:
$ numfmt --g 123456789
123,456,789
Beachten Sie, dass numfmt kein POSIX-Dienstprogramm ist, sondern Teil von GNU coreutils.
-d, --grouping
da doppelte Silbentrennungen lange Optionen erfordern?
--g
funktioniert gut für mich statt --grouping
, dh numfmt --g 1234567890
und numfmt --grouping 1234567890
mache das gleiche. Es ist ein sehr nützliches kleines Hilfsprogramm.
cat <<'EOF' |
13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096
EOF
perl -wpe '1 while s/(\d+)(\d\d\d)/$1,$2/;'
produziert:
13,407,807,929,942,597,099,574,024,998,205,846,127,479,365,820,592,393,377,723,561,443,721,764,030,073,546,976,801,874,298,166,903,427,690,031,858,186,486,050,853,753,882,811,946,569,946,433,649,006,084,096
Dies wird erreicht, indem die Ziffernfolge in 2 Gruppen aufgeteilt wird, die rechte Gruppe mit 3 Ziffern, die linke Gruppe mit allen verbleibenden Ziffern, aber mindestens einer Ziffer. Dann wird alles durch die 2 durch Komma getrennten Gruppen ersetzt. Dies wird fortgesetzt, bis die Substitution fehlschlägt. Die Optionen "wpe" dienen zur Fehlerauflistung, schließen die Anweisung in einer Schleife mit einem automatischen Ausdruck ein und nehmen das nächste Argument als Perl "program" (Details siehe Befehl perldoc perlrun).
Beste Wünsche ... Prost, drl
BASH
/ AWK
Alternative gefragt , die er möglicherweise noch nicht verwendet PERL
hat. In jedem Fall ist es am besten zu erklären, was der Befehl bewirkt - insbesondere für Einzeiler.
Mit einigen awk
Implementierungen:
echo "123456789" | awk '{ printf("%'"'"'d\n",$1); }'
123,456,789
"%'"'"'d\n"
ist: "%
(einfaches Anführungszeichen) (doppeltes Anführungszeichen) (einfaches Anführungszeichen) (doppeltes Anführungszeichen) d \ n"
Dabei wird das konfigurierte Tausendertrennzeichen für Ihr Gebietsschema verwendet (normalerweise ,
in englischer Sprache, Leerzeichen in Französisch, .
in Spanisch / Deutsch ...). Gleich wie von zurückgegebenlocale thousands_sep
Ein häufiger Anwendungsfall für mich ist es, die Ausgabe einer Befehlspipeline so zu ändern, dass Dezimalzahlen mit Tausendertrennzeichen gedruckt werden. Anstatt eine Funktion oder ein Skript zu schreiben, bevorzuge ich eine Technik, die ich spontan für jede Ausgabe aus einer Unix-Pipeline anpassen kann .
Ich habe festgestellt printf
(bereitgestellt von Awk), dass dies der flexibelste und einprägsamste Weg ist, dies zu erreichen. Das Apostroph- / Anführungszeichen wird von POSIX angegeben als Modifikator zum Formatieren von Dezimalzahlen angegeben und hat den Vorteil, dass es das Gebietsschema berücksichtigt und nicht auf die Verwendung von Kommazeichen beschränkt ist.
Wenn Sie Awk-Befehle in einer Unix-Shell ausführen, kann es schwierig sein, ein einfaches Anführungszeichen in eine durch einfache Anführungszeichen begrenzte Zeichenfolge einzugeben (um die Shell-Erweiterung von Positionsvariablen zu vermeiden, z $1
. B. ). In diesem Fall finde ich die lesbarste und zuverlässigste Möglichkeit, ein einfaches Anführungszeichen einzugeben, darin, es als oktale Escape-Sequenz (beginnend mit \0
) einzugeben .
Beispiel:
printf "first 1000\nsecond 10000000\n" |
awk '{printf "%9s: %11\047d\n", $1, $2}'
first: 1,000
second: 10,000,000
Simulierte Ausgabe einer Pipeline, aus der hervorgeht, welche Verzeichnisse den meisten Speicherplatz belegen:
printf "7654321 /home/export\n110384 /home/incoming\n" |
awk '{printf "%22s: %9\047d\n", $2, $1}'
/home/export: 7,654,321
/home/incoming: 110,384
Andere Lösungen sind in aufgeführt So vermeiden Sie ein einfaches Anführungszeichen in awk .
Hinweis: wie gegen warnte in Apostroph drucken , es wird empfohlen , die Verwendung von hexadezimalen Escape - Sequenzen zu vermeiden , da sie über verschiedene Systeme nicht zuverlässig arbeiten.
\047
.
awk
und bash
haben gute integrierte Lösungen, basierend aufprintf
, wie in den anderen Antworten beschrieben. Aber zuerst sed
.
Zum sed
müssen wir es "manuell" tun. Die allgemeine Regel lautet: Wenn Sie vier aufeinanderfolgende Ziffern gefolgt von einer Nicht-Ziffer (oder einem Zeilenende) haben, sollte ein Komma zwischen der ersten und der zweiten Ziffer eingefügt werden.
Beispielsweise,
echo 12345678 | sed -re 's/([0-9])([0-9]{3})($|[^0-9])/\1,\2\3/'
wird gedruckt
12345,678
Wir müssen dann natürlich den Vorgang wiederholen, um immer genug Kommas hinzuzufügen.
sed -re ' :restart ; s/([0-9])([0-9]{3})($|[^0-9])/\1,\2\3/ ; t restart '
In sed
gibt der t
Befehl eine Bezeichnung an, zu der gesprungen wird, wenn der letzte s///
Befehl erfolgreich war. Ich definiere daher ein Label mit :restart
, damit es zurückspringt.
Hier ist eine Bash-Demo (auf Ideone ), die mit einer beliebigen Anzahl von Ziffern funktioniert:
function thousands {
sed -re ' :restart ; s/([0-9])([0-9]{3})($|[^0-9])/\1,\2\3/ ; t restart '
}
echo 12 | thousands
echo 1234 | thousands
echo 123456 | thousands
echo 1234567 | thousands
echo 123456789 | thousands
echo 1234567890 | thousands
$ echo 1232323 | awk '{printf(fmt,$1)}' fmt="%'6.3f\n"
12,32,323.000
Wenn Sie sich GROSSE Zahlen ansehen, konnte ich die obigen Lösungen nicht zum Laufen bringen. Lassen Sie uns zum Beispiel eine wirklich große Zahl erhalten:
$ echo 2^512 |bc -l|tr -d -c [0-9]
13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096
Hinweis Ich benötige das tr
, um die Ausgabe von Backslash Newline von bc zu entfernen. Diese Zahl ist zu groß, um sie in awk als Float- oder feste Bitnummer zu behandeln, und ich möchte nicht einmal einen regulären Ausdruck erstellen, der groß genug ist, um alle Ziffern in sed zu berücksichtigen. Eher kann ich es umkehren und Kommas zwischen Gruppen von drei Ziffern setzen, dann es wieder rückgängig machen:
echo 2^512 |bc -l|tr -d -c [0-9] |rev |sed -e 's/\([0-9][0-9][0-9]\)/\1,/g' |rev
13,407,807,929,942,597,099,574,024,998,205,846,127,479,365,820,592,393,377,723,561,443,721,764,030,073,546,976,801,874,298,166,903,427,690,031,858,186,486,050,853,753,882,811,946,569,946,433,649,006,084,096
awk: run time error: improper conversion(number 1) in printf("%'d
.
a="13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096"
echo "$a" | rev | sed "s#[[:digit:]]\{3\}#&,#g" | rev
13,407,807,929,942,597,099,574,024,998,205,846,127,479,365,820,592,393,377,723,561,443,721,764,030,073,546,976,801,874,298,166,903,427,690,031,858,186,486,050,853,753,882,811,946,569,946,433,649,006,084,096
sed 's/^,//g'
.
Ich wollte auch, dass der Teil nach dem Dezimaltrennzeichen richtig getrennt / beabstandet ist, deshalb habe ich dieses sed-Skript geschrieben, das einige Shell-Variablen verwendet, um regionale und persönliche Präferenzen anzupassen. Dabei werden auch unterschiedliche Konventionen für die Anzahl der zusammen gruppierten Ziffern berücksichtigt :
#DECIMALSEP='.' # usa
DECIMALSEP=',' # europe
#THOUSSEP=',' # usa
#THOUSSEP='.' # europe
#THOUSSEP='_' # underscore
#THOUSSEP=' ' # space
THOUSSEP=' ' # thinspace
# group before decimal separator
#GROUPBEFDS=4 # china
GROUPBEFDS=3 # europe and usa
# group after decimal separator
#GROUPAFTDS=5 # used by many publications
GROUPAFTDS=3
function digitgrouping {
sed -e '
s%\([0-9'"$DECIMALSEP"']\+\)'"$THOUSSEP"'%\1__HIDETHOUSSEP__%g
:restartA ; s%\([0-9]\)\([0-9]\{'"$GROUPBEFDS"'\}\)\(['"$DECIMALSEP$THOUSSEP"']\)%\1'"$THOUSSEP"'\2\3% ; t restartA
:restartB ; s%\('"$DECIMALSEP"'\([0-9]\{'"$GROUPAFTDS"'\}\'"$THOUSSEP"'\)*\)\([0-9]\{'"$GROUPAFTDS"'\}\)\([0-9]\)%\1\3'"$THOUSSEP"'\4% ; t restartB
:restartC ; s%\([^'"$DECIMALSEP"'][0-9]\+\)\([0-9]\{'"$GROUPBEFDS"'\}\)\($\|[^0-9]\)%\1'"$THOUSSEP"'\2\3% ; t restartC
s%__HIDETHOUSSEP__%\'"$THOUSSEP"'%g'
}
A bash
/ awk
(nach Wunsch) Lösung , die unabhängig von der Länge der Anzahl und Anwendungen arbeitet ,
unabhängig von der Gebietsschema - thousands_sep
Einstellung, und überall dort , wo die Zahlen sind im Ein- und vermeidet Zugabe des Tausendertrennzeichen nach in 1.12345
:
echo not number 123456789012345678901234567890 1234.56789 |
awk '{while (match($0, /(^|[^.0123456789])[0123456789]{4,}/))
$0 = substr($0, 1, RSTART+RLENGTH-4) "," substr($0, RSTART+RLENGTH-3)
print}'
Gibt:
not number 123,456,789,012,345,678,901,234,567,890 1,234.56789
Mit awk
Implementierungen wie mawk
das nicht die Intervall regex Operatoren unterstützen, ändern Sie den regulären Ausdruck/(^|[^.0123456789])[0123456789][0123456789][0123456789][0123456789]+/
echo 123456789 | awk '$0=gensub(/(...)/,"\\1,","g")'