Відповіді:
З sed
:
$ echo "123456789" | sed 's/\([[:digit:]]\{3\}\)\([[:digit:]]\{3\}\)\([[:digit:]]\{3\}\)/\1,\2,\3/g'
123,456,789
(Зверніть увагу, що це працює лише для 9 цифр!)
або це з sed
:
$ echo "123456789" | sed ':a;s/\B[0-9]\{3\}\>/,&/;ta'
123,456,789
З printf
:
$ LC_NUMERIC=en_US printf "%'.f\n" 123456789
123,456,789
echo 123456789 | awk '$0=gensub(/(...)/,"\\1,","g"){sub(",$",""); print}'
sed
працює лише в тому випадку, якщо число становить рівно 9 цифр. printf
Не працює на Zsh. Таким чином, друга sed
відповідь, мабуть, найкраща.
echo 123456789 | awk '{printf ("%'\''d\n", $0)}'
(що, очевидно, не завжди працює на Linux !?, але працює чудово на AIX та Solaris)
bash
«S printf
підтримує майже всі , що можна зробити в printf
функції C
type printf # => printf is a shell builtin
printf "%'d" 123456 # => 123,456
printf
від coreutils зробить те саме
/usr/bin/printf "%'d" 1234567 # => 1,234,567
zsh
оновленому дописі тут .
vsnprintf
. У системі GNU / Linux, схоже, glibc підтримує її щонайменше з 1995 року.
export LC_NUMERIC="en_US"
якщо хочете застосувати коси.
locale -a
. Мені довелося скористатисьen_US.utf8
Ви можете використовувати numfmt:
$ numfmt --grouping 123456789
123,456,789
Або:
$ numfmt --g 123456789
123,456,789
Зауважте, що numfmt не є утилітою POSIX, вона є частиною ядер GNU.
-d, --grouping
оскільки подвійні переноси потребують довгих варіантів?
--g
відмінно працює для мене замість --grouping
, тобто numfmt --g 1234567890
і numfmt --grouping 1234567890
робити те ж саме. Це дуже корисна невелика утиліта.
cat <<'EOF' |
13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096
EOF
perl -wpe '1 while s/(\d+)(\d\d\d)/$1,$2/;'
виробляє:
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
Це досягається розділенням рядка цифр на 2 групи, правій групі з 3 цифрами, лівою групою, що залишилася, але щонайменше однією цифрою. Потім все замінюється двома групами, розділеними комою. Це триває, поки заміна не відбудеться. Параметри "wpe" призначені для переліку помилок, укладіть оператор всередині циклу з автоматичним друком і прийміть наступний аргумент як perl "програма" (див. Команду perldoc perlrun для деталей).
Найкращі побажання ... ура, др
BASH
/ AWK
альтернативи , щоб він не міг використовувати PERL
раніше. У будь-якому випадку, краще пояснити, що робить команда - особливо це стосується однолінійних.
З деякими awk
реалізаціями:
echo "123456789" | awk '{ printf("%'"'"'d\n",$1); }'
123,456,789
"%'"'"'d\n"
є: "%
(одинарна цитата) (подвійна цитата) (одинарна цитата) (подвійна цитата) (одинарна цитата) d \ n"
Це використовуватиме налаштований роздільник тисячі для вашої мови (як правило, ,
англійською мовою, пробіл французькою, .
іспанською / німецькою мовами ...). Те саме, що повернувlocale thousands_sep
Для мене звичайним випадком використання є модифікація виводу командного конвеєра, щоб десятичні числа друкувалися тисячами роздільниками. Замість того, щоб писати функцію чи сценарій, я вважаю за краще використовувати техніку, яку я можу налаштувати під час будь-якого виходу з конвеєра Unix.
Я знайшов printf
(наданий Awk) найбільш гнучким і незабутнім способом досягти цього. Символ апострофа / одинарної цитати визначається POSIX як модифікатор для форматування десяткових чисел і має ту перевагу, що він знає місцеві значення, тому він не обмежується використанням символів кома.
Під час виконання команд Awk з оболонки Unix можуть виникнути труднощі з введенням символу котирування синглів всередині рядка, обмеженого одинарними лапками (щоб уникнути розширення оболонки позиційних змінних, наприклад, $1
). У цьому випадку я вважаю, що найбільш читаним і надійним способом введення символу з одною цитатою є введення його як восьмеричної послідовності втечі (починаючи з \0
).
Приклад:
printf "first 1000\nsecond 10000000\n" |
awk '{printf "%9s: %11\047d\n", $1, $2}'
first: 1,000
second: 10,000,000
Модельований вихід конвеєра, який показує, які каталоги використовують найбільше дискового простору:
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
Інші рішення перераховані у розділі Як уникнути єдиної цитати в awk .
Примітка. Як застережено у друку єдиної цитати , рекомендується уникати використання шістнадцяткових послідовностей втечі, оскільки вони не працюють надійно в різних системах.
\047
.
awk
і bash
мати хороші вбудовані рішення на основі printf
, як описано в інших відповідях. Але спочатку sed
,.
Бо sed
нам це потрібно зробити "вручну". Загальне правило полягає в тому, що якщо у вас є чотири послідовні цифри, за якими слідує нецифрова цифра (або кінець рядка), кома повинна бути вставлена між першою та другою цифрами.
Наприклад,
echo 12345678 | sed -re 's/([0-9])([0-9]{3})($|[^0-9])/\1,\2\3/'
буде надруковано
12345,678
Нам, очевидно, потрібно продовжувати повторювати процес, щоб продовжувати додавати достатню кількість коми.
sed -re ' :restart ; s/([0-9])([0-9]{3})($|[^0-9])/\1,\2\3/ ; t restart '
В sed
, то t
команда визначає мітку , яка буде стрибнули в разі , якщо остання s///
команда була успішно виконана . Тому я визначаю мітку :restart
, щоб вона стрибнула назад.
Ось демонстрація bash (на ideone ), яка працює з будь-якою кількістю цифр:
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
Якщо ви дивитесь на ВЕЛИКІ номери, я не зміг змусити вищезазначені рішення. Наприклад, давайте отримаємо дійсно велику кількість:
$ echo 2^512 |bc -l|tr -d -c [0-9]
13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096
Примітка. Мені потрібно tr
видалити вихідний рядок нового рядка з bc. Це число занадто велике, щоб його розцінювати як плаваюче чи фіксоване бітове число, і я навіть не хочу будувати регулярний вираз з великим розміром, щоб враховувати всі цифри в sed. Швидше, я можу повернути його назад і поставити коми між групами з трьох цифр, а потім відмінити його:
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'
.
Я також хотів би мати частину після в десятковому роздільнику правильно відокремленому / рознесеному, тому я написав цю SED-скрипт , який використовує деякі змінні оболонки для настройки регіональних та особистих уподобань. Він також враховує різні умови щодо кількості цифр, згрупованих разом :
#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'
}
Рішення bash
/ awk
(за запитом), яке працює незалежно від довжини числа та використовує ,
незалежно від налаштування мови та 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}'
Дає:
not number 123,456,789,012,345,678,901,234,567,890 1,234.56789
З awk
такими реалізаціями mawk
, які не підтримують операторів інтервальних регулярних виразів, змініть регулярний вираз/(^|[^.0123456789])[0123456789][0123456789][0123456789][0123456789]+/
echo 123456789 | awk '$0=gensub(/(...)/,"\\1,","g")'