Ответы:
С 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 coreutils.
-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 цифрами, левую группу с тем, что осталось, но не менее одной цифры. Затем все заменяется на 2 группы, разделенные запятой. Это продолжается до тех пор, пока не произойдет замена. Параметры «wpe» предназначены для вывода списка ошибок, заключают оператор в цикл с автоматической печатью и принимают следующий аргумент в качестве «программы» perl (подробности см. В команде perldoc perlrun).
С наилучшими пожеланиями ... ура, дрл
BASH
/ AWK
альтернативу, поэтому он, возможно, не использовал PERL
раньше. В любом случае, лучше всего объяснить, что делает команда, особенно для однострочников.
С некоторыми awk
реализациями:
echo "123456789" | awk '{ printf("%'"'"'d\n",$1); }'
123,456,789
"%'"'"'d\n"
is: "%
(одинарные кавычки) (двойные кавычки) (одинарные кавычки) (двойные кавычки) (одинарные кавычки) d \ n"
Это будет использовать сконфигурированный разделитель тысяч для вашей локали (обычно ,
в английских локалях, пробел во французском, .
испанском / немецком ...). То же, что возвращеноlocale thousands_sep
Обычный вариант использования для меня - изменить вывод командного конвейера так, чтобы десятичные числа печатались с тысячами разделителей. Вместо того, чтобы писать функцию или скрипт, я предпочитаю использовать технику, которую я могу настроить на лету для любого вывода из конвейера Unix.
Я нашел printf
(предоставленный Awk) самый гибкий и запоминающийся способ для достижения этой цели. Символ апостроф / одинарная кавычка указывается POSIX как модификатор для форматирования десятичных чисел и имеет то преимущество, что он учитывает локаль, поэтому он не ограничен использованием символов запятой.
При запуске команд Awk из оболочки Unix могут возникнуть трудности при вводе символа одинарных кавычек внутри строки, разделенной одинарными кавычками (чтобы избежать расширения оболочки позиционных переменных, например, $1
). В этом случае я считаю, что наиболее читаемый и надежный способ ввести символ одинарных кавычек - это ввести его в виде восьмеричной escape-последовательности (начиная с \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 .
Примечание. Как указано в разделе « Печать одинарных кавычек» , рекомендуется избегать использования шестнадцатеричных escape-последовательностей, поскольку они не работают надежно в разных системах.
\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. Это число слишком велико, чтобы его можно было рассматривать как число с плавающей запятой или фиксированное число битов в awk, и я даже не хочу создавать регулярное выражение, достаточно большое, чтобы учесть все цифры в 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'
}
A 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")'