我正在寻找一个命令来限制从 读取的数量stdin
。
我为此目的编写了一个小脚本(欢迎批评),但我想知道是否没有一个标准命令来实现这个简单且(我认为)常见的用例。
我的脚本找到了最低限度两个数字:
#!/bin/bash
# $1 limit
[ -z "$1" ] && { echo "Needs a limit as first argument." >&2; exit 1; }
read number
if [ "$number" -gt "$1" ]; then
echo "$1"
else
echo "$number"
fi
答案1
如果您知道正在处理两个整数a
和b
,那么这些简单的使用三元运算符的 shell 算术扩展足以给出数值最大值:
$(( a > b ? a : b ))
和数值最小值:
$(( a < b ? a : b ))
例如
$ a=10
$ b=20
$ max=$(( a > b ? a : b ))
$ min=$(( a < b ? a : b ))
$ echo $max
20
$ echo $min
10
$ a=30
$ max=$(( a > b ? a : b ))
$ min=$(( a < b ? a : b ))
$ echo $max
30
$ echo $min
20
$
下面是一个 shell 脚本来演示这一点:
#!/usr/bin/env bash
[ -z "$1" ] && { echo "Needs a limit as first argument." >&2; exit 1; }
read number
echo Min: $(( $number < $1 ? $number : $1 ))
echo Max: $(( $number > $1 ? $number : $1 ))
答案2
sort
并head
可以这样做:
numbers=(1 4 3 5 7 1 10 21 8)
printf "%d\n" "${numbers[@]}" | sort -rn | head -1 # => 21
答案3
您可以仅比较两个数字dc
:
dc -e "[$1]sM $2d $1<Mp"
...其中"$1"
是您的最大值,"$2"
是您将打印的数字(如果它小于 )"$1"
。这也需要 GNU dc
- 但你可以便携式地做同样的事情,例如:
dc <<MAX
[$1]sM $2d $1<Mp
MAX
在上述两种情况下,您都可以将精度设置为 0 以外的值(默认)喜欢${desired_precision}k
。对于这两者,您还必须验证这两个值是否都是绝对是数字因为dc
可以system()
通过!
接线员拨打电话。
使用以下小脚本(以及下一个)您还应该验证输入 - 例如grep -v \!|dc
或其他东西来稳健地处理任意输入。您还应该知道用前缀而不是前缀dc
解释负数- 因为后者是减法运算符。_
-
除此之外,此脚本dc
将读取\n
您愿意提供的多个连续的行分隔数字,并为每个$max
值或输入打印,具体取决于哪个是 wo 中的较小者:
dc -e "${max}sm
[ z 0=? d lm<M p s0 lTx ]ST
[ ? z 0!=T q ]S?
[ s0 lm ]SM lTx"
所以......每一个[
方括号内的]
扩展都是一个dc
细绳每个保存到其各自数组的对象- 、或S
中的任何一个。除了一些其他的事情可能会做T
?
M
dc
细绳,它也可以将x
一个作为宏来执行。如果你安排得当,一个功能齐全的小dc
脚本就可以简单地组装起来。
dc
工作于堆。所有输入对象都堆叠在最后一个对象上 - 每个新输入对象在添加时都会将最后一个顶部对象及其下方的所有对象在堆栈上向下推一个。对对象的大多数引用都是对顶部堆栈值的引用,并且大多数引用流行音乐堆栈顶部(将其下方的所有对象拉高一)。
除了主堆栈之外,还有(至少)256 个数组,每个数组元素都有一个自己的堆栈。我在这里用的不多。我只是按照提到的方式存储字符串,这样我就可以l
在需要时加载它们并x
有条件地执行它们,并且我s
将 的值保存$max
在数组的顶部m
。
不管怎样,这一点dc
在很大程度上是你的 shell 脚本所做的事情。它确实使用了 GNU-ism-e
选项 -dc
通常从标准输入中获取其参数 - 但你可以这样做:
echo "$script" | cat - /dev/tty | dc
...如果$script
看起来像上面的位。
它的工作原理如下:
lTx
- 这l
会执行x
存储在顶部的宏T
(我猜是为了测试——我通常任意选择这些名字)。z 0=?
-T
est 然后测试堆栈深度z
,如果堆栈为空(读取:持有 0 个对象)它调用?
宏。? z0!=T q
- 该?
宏是以?
dc
从 stdin 读取一行输入的内置命令命名的,但我还z
向它添加了另一个堆栈深度测试,这样q
如果它拉入空行或命中 EOF,它就可以运行整个小程序。但如果它!
没有成功填充堆栈,则会T
再次调用 est。d lm<M
-T
est 然后将d
复制堆栈顶部并将其与$max
(如存储在m
)。如果m
是较小的值,dc
则调用M
宏。s0 lm
-M
只是弹出堆栈顶部并将其转储到虚拟标量0
- 只是弹出堆栈的一种廉价方法。在返回东部之前,它还会再次l
加载。m
T
p
- 这意味着如果m
小于当前堆栈顶部,则m
替换它(d
无论如何,它的重复)并且在这里被p
打印,否则它不会,并且无论输入是什么都会被p
打印。s0
- 之后(因为p
不会弹出堆栈)我们再次将堆栈顶部转储进去0
,然后......lTx
- 再次l
递归加载T
然后x
再次执行。
因此,您可以运行这个小代码片段,并在终端上以交互方式输入数字,然后dc
打印回您输入的数字或$max
您输入的数字较大时的值。它还会接受任何文件(例如管道)作为标准输入。它将继续读取/比较/打印循环,直到遇到空行或 EOF。
关于这一点的一些注意事项 - 我写这个只是为了模拟 shell 函数中的行为,因此它只能可靠地处理每行一个数字。dc
但是,您可以在每行处理任意数量的空格分隔的数字。然而,由于它的堆栈,一行上的最后一个数字最终成为它操作的第一个数字,因此,正如所写,dc
如果您在每行打印/键入多个数字,则会反向打印其输出。正确的方法处理方法是将一行存储在数组中,然后对其进行处理。
像这样:
dc -e "${max}sm
[ d lm<M la 1+ d sa :a z0!=A ]SA
[ la d ;ap s0 1- d sa 0!=P ]SP
[ ? z 0=q lAx lPx l?x ]S?
[q]Sq [ s0 lm ]SM 0sa l?x"
但是......我不知道我是否想更深入地解释这一点。可以这么说,当dc
读取堆栈上的每个值时,它将其值或$max
的值存储在索引数组中,并且一旦检测到堆栈再次为空,它就会在尝试读取另一个对象之前打印每个索引对象输入行。
因此,虽然第一个脚本确实...
10 15 20 25 30 ##my input line
20
20
20
15
10 ##see what I mean?
第二个是:
10 15 20 25 30 ##my input line
10 ##that's better
15
20
20 ##$max is 20 for both examples
20
如果您首先使用该命令设置它,则可以处理任意精度的浮点数k
。您可以独立地更改i
输入或o
输出基数 - 这有时会因为您可能意想不到的原因而有用。例如:
echo 100000o 10p|dc
00010
...首先将dc
的输出基数设置为 100000,然后打印 10。
答案4
您可以定义预定义数学函数库,bc
然后在命令行中使用它们。
例如,在文本文件中包含以下内容,例如~/MyExtensions.bc
:
define max(a,b){
if(a>b)
{
return(a)
}else{
return(b)
}
}
现在您可以bc
通过以下方式致电:
> echo 'max(60,54)' | bc ~/MyExtensions.bc
60
仅供参考,有免费的数学库函数比如这个可以在线获取。
使用该文件,您可以轻松计算更复杂的函数,例如GCD
:
> echo 'gcd (60,54)' | bc ~/extensions.bc -l
6