Группы процесса установлены программой, которая изменяется от корня до целевого пользователя прежде, чем выполнить программу процесса. Когда пользователь входит в систему, программа, которая изменяет пользователя, является программой входа в систему (login
, su
, sshd
, …), и программа процесса является оболочкой пользователя. Для демона, выполненного при пользователе системы, программа, которая изменяет пользователя, может быть su
или некоторый другой инструмент, такой как Debian start-stop-daemon
. Например, start-stop-daemon
всегда добавляет дополнительные группы к процессу. Изменяющая пользователя программа должна иметь логику для установки и основной группы от пользовательской базы данных и дополнительной группы от базы данных группы.
В bash
, это, вероятно, так хорошо, как это добирается. Это использует встроенную оболочку. При необходимости в результате в переменной Вы могли бы использовать замену команды, или bash
конкретный (хотя теперь также поддерживается zsh
):
printf -v int %.0f "$float"
Вы могли сделать:
float=1.23
int=${float%.*}
Но это удалило бы дробную часть вместо того, чтобы дать Вам ближайшее целое число, и это не будет работать на значения $float
как 1.2e9
или .12
например.
Также отметьте возможные ограничения из-за внутреннего представления плаваний:
$ printf '%.0f\n' 1e50
100000000000000007629769841091887003294964970946560
Вы действительно получаете целое число, но возможности состоят в том, что Вы не сможете использовать то целое число где угодно.
Кроме того, как отмечено @BinaryZebra, в нескольких printf
реализации (удар, ksh93, yash, не GNU, zsh, тире), это затронуто локалью (десятичный разделитель, который может быть .
или ,
).
Так, если Ваши плавания всегда выражаются периодом как десятичный разделитель, и Вы хотите, чтобы он рассматривался как таковой printf
независимо от локали пользователя, вызывающего Ваш сценарий, необходимо было бы прикрепить локаль к C:
LC_ALL=C printf '%.0f' "$float"
С yash
, можно также сделать:
printf '%.0f' "$(($float))"
(см. ниже).
printf "%.0f\n" 1.1
не POSIX как %f
не требуется, чтобы поддерживаться POSIX.
POSIXly, можно сделать:
f2i() {
awk 'BEGIN{for (i=1; i<ARGC;i++)
printf "%.0f\n", ARGV[i]}' "$@"
}
Тот не затронут локалью (запятая не может быть десятичным разделителем в awk
так как это уже - специальный символ в синтаксисе там (print 1,2
, то же как print 1, 2
передать два аргумента print
)
В zsh
(который поддерживает арифметику с плавающей точкой (десятичный разделитель всегда является периодом)), Вы имеете rint()
математическая функция, чтобы дать Вам ближайшее целое число как плавание (как в C
) и int()
дать Вам целое число от плавания (как в awk
). Таким образом, можно сделать:
$ zmodload zsh/mathfunc
$ i=$((int(rint(1.234e2))))
$ echo $i
123
Или:
$ integer i=$((rint(5.678e2)))
$ echo $i
568
Однако отметьте это в то время как double
s может представить очень большие количества, целые числа намного более ограничены.
$ printf '%.0f\n' 1e123
999999999999999977709969731404129670057984297594921577392083322662491290889839886077866558841507631684757522070951350501376
$ echo $((int(1e123)))
-9223372036854775808
ksh93 был первой подобной Границе оболочкой, которая будет поддерживать арифметику с плавающей точкой. ksh93 оптимизирует замену команды, не используя канал или разветвляясь, когда команды являются только встроенными командами. Так
i=$(printf '%.0f' "$f")
не разветвляется. Или еще лучше:
i=${ printf '%.0f' "$f"; }
который не разветвляет ни одного, но также и не идет вся проблема создать поддельную подсреду оболочки.
Можно также сделать:
i=$((rint(f)))
Но остерегайтесь:
$ echo "$((rint(1e18)))"
1000000000000000000
$ echo "$((rint(1e19)))"
1e+19
Вы могли также сделать:
integer i=$((rint(f)))
Но как для zsh
:
$ integer i=1e18
$ echo "$i"
1000000000000000000
$ integer i=1e19
$ echo "$i"
-9223372036854775808
Остерегайтесь этого ksh93
арифметика с плавающей точкой соблюдает десятичную установку разделителя в локали (даже при том, что ,
иначе математический оператор ($((1,2))
был бы 6/5 во французах/Немце... локаль и то же как $((1, 2))
, это 2 в английской локали).
yash также поддерживает арифметику с плавающей точкой, но не имеет математических функций как ksh93
/zsh
rint()
. Можно преобразовать число в целое число, хотя при помощи двоичного файла или оператора, например (также работает в zsh
но не в ksh93
). Обратите внимание однако, что это усекает десятичную часть, это не дает Вам ближайшее целое число:
$ echo "$((0.237e2 | 0))"
23
$ echo "$((1e19))"
-9223372036854775808
yash
соблюдает десятичный разделитель локали на выводе, но не для литеральных констант с плавающей точкой в его арифметических выражениях, которые могут вызвать неожиданности:
$ LC_ALL=fr_FR.UTF-8 ./yash -c 'a=$((1e-2)); echo $(($a + 1))'
./yash: arithmetic: `,' is not a valid number or operator
Это хорошо способом, в котором можно использовать константы с плавающей точкой в сценариях, которые используют период и не имеют, чтобы волноваться, что это прекратит работать в других локалях, но все еще мочь иметь дело с числами, как выражено пользователем, пока Вы не забываете делать:
var=$((10.3)) # and not var=10.3
... "$((a + 0.1))" # and not "$(($a + 0.1))".
printf '%.0f\n' "$((10.3))" # and not printf '%.0f\n' 10.3
bc
- Язык калькулятора произвольной точности
интервал (плавание) должен быть похожим:
$ echo "$float/1" | bc
1234
К круглому лучше используют это:
$ echo "($float+0.5)/1" | bc
Пример:
$ float=1.49
$ echo "($float+0.5)/1" | bc
1
$ float=1.50
$ echo "($float+0.5)/1" | bc
2
Очень простой способ взлома -
function float_to_int() {
echo $1 | cut -d. -f1 # or use -d, if decimals separator is ,
}
Пример вывода
$ float_to_int 32.333
32
$ float_to_int 32
32
Предыдущий ответ был почти правильным: «Вы могли бы сделать:
float=1.23
int=${float%.*}
Но это удалило бы дробную часть вместо того, чтобы дать вам ближайшее целое число и это не будет работать для значений $ float, например, 1.2e9 или .12 .... "
Просто используйте $ {float %%. *}
.
echo ${float%%.*}
1
Похожие:
Дополнение @Stéphane Chazelasawk
ответ:
float_to_integer_rounding_nearst() {
awk 'BEGIN{for (i=1; i<ARGC;i++) printf "%.0f", ARGV[i]}' "$@";
}
float_to_integer_rounding_floor() {
awk 'BEGIN{for (i=1; i<ARGC;i++) printf "%d", int( ARGV[i] )}' "$@";
}