Yanıtlar:
İle sed
:
$ echo "123456789" | sed 's/\([[:digit:]]\{3\}\)\([[:digit:]]\{3\}\)\([[:digit:]]\{3\}\)/\1,\2,\3/g'
123,456,789
(Bunun yalnızca tam 9 rakam için çalıştığını unutmayın!)
veya bununla sed
:
$ echo "123456789" | sed ':a;s/\B[0-9]\{3\}\>/,&/;ta'
123,456,789
İle printf
:
$ LC_NUMERIC=en_US printf "%'.f\n" 123456789
123,456,789
echo 123456789 | awk '$0=gensub(/(...)/,"\\1,","g"){sub(",$",""); print}'
sed
sadece rakam tam olarak 9 rakam ise işe yarar. printf
Zsh üzerinde çalışmaz. Böylece ikinci sed
cevap muhtemelen en iyisidir.
echo 123456789 | awk '{printf ("%'\''d\n", $0)}'
(açıkça Linux'ta çalışmaz!?, Ama AIX ve Solaris'te iyi çalışır)
bash
bireyin printf
destekler hemen hemen her şeyi yapabilirsiniz printf
C fonksiyonu
type printf # => printf is a shell builtin
printf "%'d" 123456 # => 123,456
printf
coreutils den aynı şeyi yapacak
/usr/bin/printf "%'d" 1234567 # => 1,234,567
zsh
de, burada güncellenen yazı olarak desteklenmektedir .
vsnprintf
. Bir GNU / Linux sisteminde, glibc, en azından 1995'ten beri bunu desteklemiş görünüyor.
export LC_NUMERIC="en_US"
Virgül zorlamak istersen yapabilirsin .
locale -a
. en_US.utf8
Numfmt kullanabilirsiniz:
$ numfmt --grouping 123456789
123,456,789
Veya:
$ numfmt --g 123456789
123,456,789
Numfmt'nin bir POSIX yardımcı programı olmadığını, GNU coreutils'in bir parçası olduğunu unutmayın.
-d, --grouping
çift tirelemelerin uzun seçeneklere ihtiyaç duymasından dolayı gibi bir şey mi yazdınız ?
--g
yerine benim için para cezası çalışır --grouping
, yani numfmt --g 1234567890
ve numfmt --grouping 1234567890
aynı şeyi yapın. Çok kullanışlı bir yardımcı program.
cat <<'EOF' |
13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096
EOF
perl -wpe '1 while s/(\d+)(\d\d\d)/$1,$2/;'
üretir:
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
Bu, rakam dizesini 2 gruba, sağ gruba 3 hane, sol gruba kalanı sol gruba ayırarak gerçekleştirilir, ancak en az bir hane. Sonra her şey virgülle ayrılmış 2 grupla değiştirilir. Bu, ikame başarısız olana kadar devam eder. "Wpe" seçenekleri hata listeleme içindir, ifadeyi otomatik yazdırmalı bir döngü içine alın ve bir sonraki argümanı perl "program" olarak alın (ayrıntılar için perldoc perlrun komutuna bakın).
En iyi dileklerimle ... şerefe, drl
BASH
/ AWK
Kullandığı olmayabilir bu yüzden alternatif PERL
önce. Her durumda, komutun ne yaptığını açıklamak en iyisi - özellikle tek gömlekler için.
Bazı awk
uygulamalarda:
echo "123456789" | awk '{ printf("%'"'"'d\n",$1); }'
123,456,789
"%'"'"'d\n"
şudur: "%
(tekli teklif) (çiftli teklif) (tekli teklif) (çiftli teklif) (tekli teklif) d \ n"
Bu, yerel ayarlarınız için yapılandırılmış bin ayırıcıyı kullanacaktır (genellikle ,
İngilizce yerel yerlerde, Fransızca'da, .
İspanyolca'da / Almanca'da ...). Tarafından döndürülenle aynılocale thousands_sep
Benim için yaygın bir kullanım örneği, bir komut satırının çıktısını, ondalık sayıları bin ayracı ile yazdırılacak şekilde değiştirmek. Bir işlev veya komut dosyası yazmak yerine , bir Unix boru hattından gelen herhangi bir çıktı için anında özelleştirebileceğim bir teknik kullanmayı tercih ederim .
Bunu printf
yapmanın en esnek ve akılda kalıcı yolu olarak (Awk tarafından sağlanan) buldum . Kesme işareti / tek tırnak karakteri POSIX tarafından ondalık sayıları biçimlendirmek için bir değiştirici olarak belirtilmiştir ve yerel olarak farkında olma avantajına sahiptir, bu nedenle virgül karakterleri kullanmakla sınırlı değildir.
Bir Unix kabuğundan Awk komutlarını çalıştırırken, tek tırnak işaretleri ile sınırlandırılmış bir dize içine bir alıntı karakter girme zorluğu olabilir (örneğin, konumsal değişkenlerin kabuk genişlemesini önlemek için $1
). Bu durumda, tek alıntı karakterine girmenin en okunaklı ve güvenilir yolunu buluyorum, onu sekizli bir kaçış dizisi olarak girmektir (baştan \0
).
Örnek:
printf "first 1000\nsecond 10000000\n" |
awk '{printf "%9s: %11\047d\n", $1, $2}'
first: 1,000
second: 10,000,000
Hangi dizinlerin en fazla disk alanını kullandığını gösteren bir boru hattının simüle çıkışı:
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
Diğer çözümler awk içinde tek bir alıntıdan nasıl kaçılır .
Not: Tek Bir Alıntı Basında uyarıldığı gibi , onaltılık kaçış dizilerinin farklı sistemlerde güvenilir şekilde çalışmadıklarından kaçınılması önerilir.
\047
.
awk
ve diğer cevaplarda açıklandığı şekilde bash
, iyi yerleşik çözümler sunar printf
. Ama önce, sed
.
Çünkü sed
"elle" yapmamız gerekiyor. Genel kural, arka arkaya dört basamağa sahipseniz, ardından basamak olmayan (veya satır sonu) ise, birinci ve ikinci basamak arasına virgül konması gerektiğidir.
Örneğin,
echo 12345678 | sed -re 's/([0-9])([0-9]{3})($|[^0-9])/\1,\2\3/'
basacak
12345,678
Açıkçası, yeterince virgül eklemeye devam etmek için süreci tekrarlamaya devam etmemiz gerekiyor.
sed -re ' :restart ; s/([0-9])([0-9]{3})($|[^0-9])/\1,\2\3/ ; t restart '
Olarak sed
, t
komut son takdirde atladı edilecek bir etiket belirten s///
komut başarılı oldu. Bu nedenle :restart
, geri sıçraması için ile bir etiket tanımlarım .
İşte herhangi bir rakam ile çalışan bir bash demosu ( ideone üzerinde ):
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
Eğer BÜYÜK rakamlara bakıyorsanız yukarıdaki çözümleri çalıştıramadım. Örneğin, gerçekten büyük bir sayı elde edelim:
$ echo 2^512 |bc -l|tr -d -c [0-9]
13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096
Not tr
Ters eğik çizgi newline çıktısını bc'den çıkarmam gerekiyor. Bu sayı awk içinde bir float veya sabit bit numarası olarak değerlendirilemeyecek kadar büyük ve sed içindeki tüm rakamları hesaba katacak kadar büyük bir regexp oluşturmak bile istemiyorum. Aksine, onu tersine çevirebilir ve üç basamaklı gruplar arasına virgül koyabilir, sonra tersine çevirebilirim:
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'
.
Ayrıca bir kısım olsun istedim sonra ondalık ayırıcı doğru / ayrılmış aralıklı, bu nedenle bölgesel ve kişisel tercihlerine ayarlamak için bazı kabuk değişkenlerini kullanan bu sed-senaryoyu yazdım. Ayrıca, birlikte gruplandırılmış hane sayısı için farklı kuralları da dikkate alır :
#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'
}
Sayının uzunluğundan bağımsız olarak çalışan ve yerel ayarın ne olduğuna bakılmaksızın çalışan ve sayıların girildiği her yerde çalışan ve aşağıdakilerden sonra bin ayırıcıyı eklemekten kaçınan A bash
/ awk
(istendiği gibi) çözümü :,
thousands_sep
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}'
verir:
not number 123,456,789,012,345,678,901,234,567,890 1,234.56789
Düzenli regex operatörlerini desteklemeyen awk
gibi uygulamalarla mawk
regexp'yi değiştirin./(^|[^.0123456789])[0123456789][0123456789][0123456789][0123456789]+/
echo 123456789 | awk '$0=gensub(/(...)/,"\\1,","g")'