stdin
から読み取られる数を制限するコマンドを探していました。
私はその目的のために小さなスクリプトを書きました(批評は歓迎します)が、これに対する標準的なコマンドがなく、単純で(私が思うに)一般的な使用例がないのではないかと思っていました。
2つの数値のminimumを見つけるスクリプト:
#!/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
次のように、2つの数値だけをdc
と比較できます。
_dc -e "[$1]sM $2d $1<Mp"
_
...ここで_"$1"
_は最大値であり、_"$2"
_は_"$1"
_よりも小さい場合に出力する数値です。これにはGNU dc
も必要ですが、同じように移植可能です。
_dc <<MAX
[$1]sM $2d $1<Mp
MAX
_
上記のどちらの場合でも、_${desired_precision}k
_のように、精度を0以外(デフォルト)に設定できます。どちらの場合も、dc
がsystem()
呼び出しを実行できるため、両方の値が確実に数値であることを確認する必要がありますw/_!
_演算子。
次の小さなスクリプト(および次の)を使用して、_grep -v \!|dc
_または任意の入力を確実に処理するための何かなどの入力も確認する必要があります。 dc
は負の数値を__
_接頭辞ではなく_-
_接頭辞で解釈することも知っておく必要があります。後者は減算演算子だからです。
それとは別に、このスクリプトを使用すると、dc
は、必要な数の連続する_\n
_ ewlineで区切られた数値を読み取り、_$max
_値または入力ごとに出力します。どちらが小さいのかに応じて:
_dc -e "${max}sm
[ z 0=? d lm<M p s0 lTx ]ST
[ ? z 0!=T q ]S?
[ s0 lm ]SM lTx"
_
つまり... _[
_角かっこ__]
_の各展開は、dc
stringオブジェクトであり、 S
avedそれぞれをそれぞれの配列に-T
、_?
_、またはM
のいずれか。 dc
がstringで実行できる他のいくつかの処理に加えて、マクロとしてe x
ecuteを実行することもできます。正しく配置すると、完全に機能する小さなdc
スクリプトが簡単に組み立てられます。
dc
はstackで機能します。すべての入力オブジェクトは最後に積み重ねられます-新しい入力オブジェクトはそれぞれ、最後の一番上のオブジェクトとその下のすべてのオブジェクトを、追加されると1つずつスタックに押し下げます。オブジェクトへのほとんどの参照は、トップスタック値への参照であり、ほとんどの参照popスタックのトップ(これは、その下のすべてのオブジェクト)。
メインスタックの他に、(少なくとも)256配列もあり、各配列要素には独自のスタックが付属しています。ここではあまり使いません。前述のように文字列を格納するだけなので、必要に応じてそれらをl
oadし、条件付きでe x
ecuteできます。また、s
tore _$max
_の値をm
配列。
とにかく、このdc
のほんの少しは、主にシェルスクリプトが行うことを実行します。 GNU-ism _-e
_オプションを使用します-dc
は通常、そのパラメーターを標準入力から取得しますが、次のように同じことを行うことができます。
_echo "$script" | cat - /dev/tty | dc
_
..._$script
_が上記のビットのように見えた場合。
それは次のように機能します:
lTx
-これはl
oadsおよびe x
e _T
の先頭に格納されているマクロを実行します(テスト用と思います-私は通常、それらの名前を任意に選択します)。z 0=?
_-T
est次に、スタック深度をz
でテストし、スタックが空の場合(読み取り:0オブジェクトを保持)_?
_マクロを呼び出します。? z0!=T q
_-_?
_マクロは、stdinから入力行を読み取る_?
_ dc
組み込みコマンドの名前ですが、別のz
も追加しましたスタック深度テストを実行して、空の行をプルしたりEOFにヒットした場合にプログラム全体をq
uitできるようにします。ただし、_!
_ notを実行し、代わりに正常にスタックにデータを入力した場合は、T
estを再度呼び出します。d lm<M
_-T
estは、スタックの先頭をd
uplicateし、_$max
_と比較します(m
)。 m
が小さい値の場合、dc
はM
マクロを呼び出します。s0 lm
_-M
はスタックの先頭をポップし、ダミースカラーにダンプします_0
_-スタックをポップする安価な方法です。また、l
estに戻る前に、再度m
oads T
します。p
-これは、m
が現在のスタックの最上位よりも小さい場合、m
がそれを置き換える(the d
uplicate、anyway)そしてここにp
rintedがあり、それ以外の場合はそうではなく、代わりに入力がp
rintedになります。s0
_-その後(p
はスタックをポップしないため)スタックの先頭を_0
_再び、そして...lTx
-再帰的にl
oad T
estその後、もう一度e x
ecuteしてください。したがって、この小さなスニペットを実行し、端末で対話的に数値を入力すると、dc
は入力した数値、または入力した数値が大きい場合は_$max
_の値を出力します。また、標準入力として任意のファイル(パイプなど)を受け入れます。空白行またはEOFが見つかるまで、読み取り/比較/印刷ループを続けます。
ただし、これに関するいくつかの注意事項-これは、シェル関数の動作をエミュレートするためだけに作成したため、1行あたり1つの数値のみを確実に処理します。ただし、dc
は、スペースで区切られた1行あたりの数値を、必要な数だけ処理できます。 ただし、、そのスタックのため、行の最後の数値は最初に処理されるため、dc
は、1行に複数の数値を印刷または入力した場合、その出力を逆に印刷します。これを処理する適切な方法は、配列に行を格納し、それを処理することです。
このような:
_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?
_
2つ目は:
_10 15 20 25 30 ##my input line
10 ##that's better
15
20
20 ##$max is 20 for both examples
20
_
最初にk
コマンドで設定すると、任意精度の浮動小数点数を処理できます。また、i
nputまたはo
utputの基数を個別に変更できます。これは、予期しない理由で役立つ場合があります。例えば:
_echo 100000o 10p|dc
00010
_
...最初にdc
の出力基数を100000に設定し、次に10を出力します。
2つの整数a
とb
を扱っていることがわかっている場合は、これらの単純な 三項演算子を使用したシェルの算術展開 で数値の最大値を得ることができます。
$(( 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
$
これを示すシェルスクリプトは次のとおりです。
#!/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 ))
sort
とhead
はこれを行うことができます:
numbers=(1 4 3 5 7 1 10 21 8)
printf "%d\n" "${numbers[@]}" | sort -rn | head -1 # => 21
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
コメントが長すぎます:
あなたはこれらのことを行うことができますが、例えば_sort | head
_または_sort | tail
_コンボでは、リソースおよびエラー処理の両方の面でどちらかと言えば最適ではないようです。実行に関する限り、コンボは2行をチェックするためだけに2つのプロセスを生成することを意味します。それは少しやり過ぎのようです。
より深刻な問題は、ほとんどの場合、あなたが知る必要があるのは、入力が正気であること、つまり数値しか含まれていないことです。 @ glennjackmann's solution _printf %d
_は非整数でバーフする必要があるため、これを巧みに解決します。浮動小数点数でも機能しません(書式指定子を_%f
_に変更しない限り、丸めの問題が発生します)。
_test $1 -gt $2
_は、比較が失敗したかどうかを示します(終了ステータス2は、テスト中にエラーが発生したことを意味します。これは通常、Shell組み込みであるため、追加のプロセスは生成されません。何百倍も速い実行の話ですが、整数のみで動作します。
いくつかの浮動小数点数を比較する必要がある場合、興味深いオプションはbc
です。
_define x(a, b) {
if (a > b) {
return (a);
}
return (b);
}
_
_test $1 -gt $2
_と同等であり、シェルで使用します。
_max () { printf '
define x(a, b) {
if (a > b) {
return (a);
}
return (b);
}
x(%s, %s)
' $1 $2 | bc -l
}
_
_printf | sort | head
_(2つの数値の場合)よりも、ほぼ2.5倍高速です。
GNU bc
の拡張機能)を信頼できる場合は、read()
関数を使用して数値を直接bc
に読み込むこともできます。スリップ。
次のように関数を定義できます。
maxnum(){
if [ $2 -gt $1 ]
then
echo $2
else
echo $1
fi
}
maxnum 54 42
とエコーします54
。必要に応じて、関数内に検証情報(2つの引数または引数としての数値など)を追加できます。
$ aと$ bのより大きな値を取得するには、これを使用します。
[ "$a" -gt "$b" ] && $a || $b
しかし、あなたはその周りに何かが必要です、あなたはおそらく数を実行することを意味しないので、2つの使用のより大きな値を表示するには「エコー」を使用します
[ "$a" -gt "$b" ] && echo $a || echo $b
上記はシェル関数にうまく適合します、例えば
max() {
[ "$1" -gt "$2" ] && echo $1 || echo $2
}
2つのうち大きい方を変数に割り当てるには、次の修正バージョンを使用します。
[ "$a" -gt "$b" ] && biggest=$a || biggest=$b
または定義された関数を使用します:
biggest=$( max $a $b )
関数のバリエーションでは、入力エラーチェックを適切に追加することもできます。
2つの10進数/浮動小数点数の最大値を返すには、awk
を使用できます
decimalmax() {
echo $1 $2 | awk '{if ($1 > $2) {print $1} else {print $2}}';
}
編集:このテクニックを使用して、編集/ノートごとに逆に動作する「制限」関数を作成できます。この関数は2つのうち小さい方を返します。例:
limit() {
[ "$1" -gt "$2" ] && echo $2 || echo $1
}
ユーティリティ関数を別のファイルに入れてmyprogram.funcs
と呼び、スクリプトで次のように使用します。
#!/bin/bash
# Initialization. Read in the utility functions
. ./myprogram.funcs
# Do stuff here
#
[ -z "$1" ] && { echo "Needs a limit as first argument." >&2; exit 1; }
read number
echo $( limit $1 $number )
FWIWでもこれはあなたがやったことをし、あなたのバージョンはもっと冗長ですが、同じくらい効率的です。
よりコンパクトな形式は実際には優れていませんが、スクリプトが乱雑になるのを防ぎます。単純なif-then-else-fi構成が多数ある場合、スクリプトは急速に拡大します。
1つのスクリプトで大きい数/小さい数のチェックを複数回再利用する場合は、関数に入れます。関数形式を使用すると、デバッグと再利用が容易になり、スクリプトのその部分を簡単に置き換えることができます。たとえば、整数でない10進数を処理できるawkコマンドを使用できます。
単一のユースケースの場合は、インラインでコーディングするだけです。
シェルスクリプトから、anyJava public static method(and exampleMath。 min())。Linuxのbashから:
. jsbInit
jsbStart
A=2
B=3
C=$(jsb Math.min "$A" "$B")
echo "$C"
これにはJava Shell Bridgehttps://sourceforge.net/projects/jsbridge/ が必要です
メソッドの呼び出しは内部的にpipedなので、非常に高速です。プロセスは必要ありません。
ほとんどの人は_sort -n input | head -n1
_(または末尾)を実行するだけで、ほとんどのスクリプト状況に十分対応できます。ただし、列ではなく行に数値がある場合、これは少し不格好です。適切な形式(_tr ' ' '\n'
_または類似の形式)で出力する必要があります。
シェルは数値処理には必ずしも理想的ではありませんが、優れた他のプログラムにパイプするだけで簡単にできます。自分の好みに応じて、dc
(少し難読化されていますが、何をしているかわかっている場合は問題ありません-mikeservの回答を参照してください)、またはawk 'NR==1{max=$1} {if($1>max){max=$1}} END { print max }'
を最大呼び出しします。または、必要に応じてPerl
またはpython
を使用することもできます。 1つの解決策(あまり知られていないソフトウェアをインストールして使用する場合)はised
です(特に、データが1行の場合:_ised --l input.dat 'max$1'
_を実行するだけです)。
2つの数値を求めているため、これはすべてやりすぎです。これで十分です:
_python -c "print(max($j,$k))"
_