В:
cat test | xargs -I% bash -c 'echo % $1 $2;'
$1
и $2
передаются как литеральные строки в аргументе bash -c
, то есть встроенному сценарию -. И %
также будет расширен в этом скрипте, поэтому будет рассматриваться как шелл-код. Так, например, если test
содержит ;reboot;
, это вызовет команду reboot
.
Вы не передаете аргументы этому встроенному скрипту, поэтому $1
, $2
будут пустыми.
Вы могли бы сделать:
< test xargs -I% bash -c 'echo "$1" "$2" "$3"' bash % "$1" "$2"
Чтобы перенаправить аргумент вашего скрипта в ваш встроенный скрипт, но если $1
или $2
также содержат символы %
, они также будут расширены на xargs
.
Таким образом, вместо этого вы можете использовать среду для передачи этих значений:
< test PARAM1=$1 PARAM2=$2 xargs -I% bash -c '
echo "$1" "$PARAM1" "$PARAM2"' bash %
Также обратите внимание, что xargs
выполняет некоторую обработку кавычек на входе, если вы хотите, чтобы необработанное содержимое каждой строки передавалось дословно, это не то, что вы бы использовали. С GNU xargs
вы могли бы сделать:
< test xargs -d '\n' -n 1 bash -c 'echo "$3" "$1" "$2"' bash "$1" "$2"
Кроме того, не забудьте указать свои переменные в кавычках. printf
более надежен, чем echo
, но помните, что первый аргумент — это формат , поэтому не должен быть переменной .
Выполнение математических операций, результатом которых является 25 цифр (3706907995955475988644381
), безусловно, выходит за рамки возможностей большинства реализаций оболочки. На самом деле арифметика оболочки очень похожа на арифметику языка C. В языке C целое число со знаком меняет знак при переполнении. Обычно самое длинное системное целое для 64-битной системы имеет значение, ограниченное 63 двоичными цифрами (, другой бит определяет знак целого числа ), поэтому 63 единицы в двоичном или 0efff ffff ffff ffff в шестнадцатеричном представлении число $(((1<<63)-1 ))или 9223372036854775807 (19 цифр ). Отрицательный предел равен -9223372036854775808.
25-значное число не может поместиться внутри 19-значного целого, поэтому оно переполняется, так как Целые числа со знаком C переполняются:при смене знака (на большинстве машин):
$ echo "$(( 9223372036854775807 + 1 ))"
-9223372036854775808
Язык самого низкого уровня, который (автономная )утилита может обеспечить для чисел "произвольной точности" (без предустановленного ограничения длины ), — это bc. В bc нетрудно выполнить все требование:
x=12345
y=2
scale=0;
s=0;
while (x>0) {
b=x%10;
x/=10;
s+=b^y
};
s
quit
Запишите это в файл (предположим, что он называетсяdigpower.bc
)и выполните с этим:
$ bc -q digpower.bc
55
Преобразование всего файла, чтобы он содержал только функцию, которая заботится о временных переменных и возвращает масштаб к исходному значению:
define d(x,y){
auto s,b,u; s=scale;
while (x>0) { b=x%10; x/=10; u+=b^y }
scale=s; return(u) };
В этом случае вызовите bc следующим образом:
$ bc -q digpower.bc <<<"d(12345,2)"
55
$ echo "d(3706907995955475988644381,25)" | bc digpower.bc
3706907995955475988644381
Следующим языком более высокого уровня (, пропускающим Common lisp ), который имеет неограниченный (только компьютерной памяти )целые числа, является Python:
$ python3 -c 'x=12345;y=2;s=0;
while (x>0): b=x%10;x//=10;s+=b**y
print(s)'
55
В большинстве других языков используются те или иные формы чисел с плавающей запятой, в том числе awk
. Некоторые языки позволяют устанавливать размер числа с плавающей запятой (подробнее об этом в последней версии awk ).
Все числа внутри awk
хранятся как числа с плавающей запятой. По умолчанию awk использует 53-битную мантиссу. 53-битная мантисса имеет общее ограничение в 16 цифр.В некоторых конкретных поплавках может быть точно 17 или даже 18 цифр.
$ awk -vx=12345 -vy=2 'BEGIN{s=0;while(x>0){b=x%10;x=int(x/10);s+=b^y}; print(s)}'
55
Но (тот же код с другими значениями):
$ awk -vx=3706907995955475988644381 -vy=25 'BEGIN{s=0;while(x>0){b=x%10;x=int(x/10);s+=b^y}; print(s)}'
2989038141653481752100864
Что, очевидно, неверно, потому что внутреннее представление в виде числа с плавающей запятой становится совершенно неверным после 16-значного числа. Просто чтобы показать это:
$ awk -vx=3706907995955475988644381 'BEGIN{print(x);print(x+0)}'
3706907995955475988644381
3706907995955475754516480
Эти ошибки приводят к большим ошибкам.
В GNU awk существует альтернатива увеличения числа битов мантиссы с плавающей запятой, если awk имеет bignum, скомпилированный в (вывод версии awk --содержит «GNU MPFR»):
$ awk -M -v PREC=100 -vx=3706907995955475988644381 -vy=25 'BEGIN{s=0;while(x>0){b=x%10;x=int(x/10);s+=b**y}; print(s)}'
3706907995955475988644381
25-значная цифра требует около 25*log(2)/log(10)
двоичных цифр или 83-битной мантиссы (точный ответ довольно долго объяснять ). Использование 100 дает достаточный запас.
Арифметика оболочки в bash
использует самый широкий целочисленный тип, поддерживаемый вашим компилятором C. В большинстве современных систем/компиляторов C это 64-битные целые числа, поэтому «только» охватывают диапазон -9223372036854775808 до 9223372036854775807 и обертывают числа вне этого. Для этого вам понадобится другой инструмент, например bc :
#!/bin/bash
num1=$1
num2=$2
sum=0
for (( i=0; i<${#num1}; i++ )); do
n=${num1:$i:1}
sum=$( bc <<<"$sum + $(bc <<<"${n}^$num2")" )
done
echo "$sum"
С короткимawk
шрифтом:
sum_powered.awk
скрипт:
#!/bin/awk -f
BEGIN{
split(ARGV[1], a, "");
pow = ARGV[2];
for (i in a) sum += a[i] ** pow;
print sum;
}
Использование:
$./sum_powered.awk 12345 2
55
$./sum_powered.awk 3706907995955475988644381 25
3706907995955475217645568
Возможно, вам потребуется добавить разрешение на выполнение для нового awk скрипта перед запуском:
$ chmod +x sum_powered.awk