Você pode comparar apenas dois números com os seguintes dc
:
dc -e "[$1]sM $2d $1<Mp"
... onde "$1"
está seu valor máximo e "$2"
é o número que você imprimiria se for menor que "$1"
. Isso também requer o GNU dc
- mas você pode fazer o mesmo de maneira portável:
dc <<MAX
[$1]sM $2d $1<Mp
MAX
Em ambos os casos acima, você pode definir a precisão para algo diferente de 0 (o padrão) como ${desired_precision}k
. Para ambos, também é imperativo que você verifique se os dois valores são definitivamente números, pois dc
podem fazer system()
chamadas com o !
operador.
Com o pequeno script a seguir (e o próximo), você deve verificar a entrada também - grep -v \!|dc
ou algo assim - para lidar com entrada arbitrária de maneira robusta. Você também deve saber que dc
interpreta números negativos com um _
prefixo em vez de um -
prefixo - porque o último é o operador de subtração.
Além disso, com esse script, dc
você lerá o número sequencial de \n
números de linha de ew que você gostaria de fornecê-lo e imprimirá para cada um o seu $max
valor ou a entrada, dependendo de qual é o menor dos dois:
dc -e "${max}sm
[ z 0=? d lm<M p s0 lTx ]ST
[ ? z 0!=T q ]S?
[ s0 lm ]SM lTx"
Então ... cada um desses [
colchetes quadrados ]
extensões é uma dc
seqüência de objeto que é S
AVED cada um para seu respectivo array - qualquer um dos T
, ?
ou M
. Além de algumas outras coisas que dc
podem fazer com uma string , ela também pode ser x
reproduzida como uma macro. Se você acertar, um pequeno dc
script totalmente funcional será montado com bastante simplicidade.
dc
trabalha em uma pilha . Todos os objetos de entrada são empilhados, cada um sobre o último - cada novo objeto de entrada pressionando o último objeto superior e todos os objetos abaixo dele na pilha por um à medida que são adicionados. A maioria das referências a um objeto são para o valor superior da pilha, ea maioria das referências pop que topo da pilha (que puxa todos os objetos abaixo-lo por um) .
Além da pilha principal, também existem (pelo menos) 256 matrizes e cada elemento da matriz vem com uma pilha própria. Eu não uso muito disso aqui. Eu apenas guardo as strings conforme mencionado para poder l
carregá-las quando desejado e x
calculá-las condicionalmente, e s
rasguei $max
o valor na parte superior da m
matriz.
Enfim, esse pouco dc
faz, em grande parte, o que o seu shell-script faz. Ele usa a -e
opção GNU-ism - como dc
geralmente tira seus parâmetros do padrão - mas você pode fazer o mesmo como:
echo "$script" | cat - /dev/tty | dc
... se $script
parecia com a parte acima.
Funciona como:
lTx
- Isso l
apaga e faz x
eco da macro armazenada no topo T
(para teste, eu acho - eu geralmente escolho esses nomes arbitrariamente) .
z 0=?
- T
est testa a profundidade da pilha w / z
e, se a pilha estiver vazia (leia-se: contém 0 objetos) , chama a ?
macro.
? z0!=T q
- A ?
macro é nomeada para o ?
dc
comando embutido que lê uma linha de entrada do stdin, mas também adicionei outro z
teste de profundidade da pilha, para que ele possa q
utilizar todo o pequeno programa se puxar uma linha em branco ou atingir o EOF. Mas se não !
preencher e preencher com êxito a pilha, ela chamará T
est novamente.
d lm<M
- T
est então d
duplicará a parte superior da pilha e comparará com $max
(conforme armazenado em m
) . Se m
for o menor valor, dc
chama a M
macro.
s0 lm
- M
apenas abre a parte superior da pilha e a despeja no escalar fictício 0
- apenas uma maneira barata de estourar a pilha. Também se l
recupera m
antes de retornar ao T
est.
p
- Isso significa que, se m
for menor que o topo da pilha atual, a m
substitui (a d
cópia da mesma, de qualquer maneira) e fica aqui p
definida, caso contrário, não existe e o que quer que a entrada tenha sido p
definida.
s0
- Depois (porque p
não abre a pilha) , despejamos o topo da pilha 0
novamente e depois ...
lTx
- recursivamente l
oad T
est mais uma vez, em seguida, e x
ecute-lo novamente.
Assim, você pode executar esse pequeno trecho e digitar números de forma interativa no seu terminal e dc
imprimir de volta o número digitado ou o valor $max
se o número digitado for maior. Também aceitaria qualquer arquivo (como um pipe) como entrada padrão. Ele continuará o loop de leitura / comparação / impressão até encontrar uma linha em branco ou EOF.
Algumas observações sobre isso - eu escrevi isso apenas para emular o comportamento da função shell, portanto, ele apenas lida com um número por linha. dc
No entanto, você pode lidar com tantos números separados por espaço por linha quanto gostaria de jogar nela. No entanto , devido à sua pilha, o último número de uma linha acaba sendo o primeiro em que opera, e, como está escrito, dc
imprimiria sua saída ao contrário se você imprimisse / digitasse mais de um número por linha nela. lidar com isso é armazenar uma linha em uma matriz e depois trabalhá-la.
Como isso:
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"
Mas ... não sei se quero explicar isso com tanta profundidade. Basta dizer que, ao dc
ler cada valor da pilha, ele armazena seu valor ou $max
seu valor em uma matriz indexada e, uma vez que detecta a pilha novamente vazia, ele imprime cada objeto indexado antes de tentar ler outro linha de entrada.
E assim, enquanto o primeiro script faz ...
10 15 20 25 30 ##my input line
20
20
20
15
10 ##see what I mean?
O segundo faz:
10 15 20 25 30 ##my input line
10 ##that's better
15
20
20 ##$max is 20 for both examples
20
Você pode manipular carros alegóricos de precisão arbitrária se primeiro configurá-lo com o k
comando E você pode alterar os radios nput i
ou o
utput independentemente - o que às vezes pode ser útil por razões que você não pode esperar. Por exemplo:
echo 100000o 10p|dc
00010
... que define o primeiro dc
raio de saída para 100000 e depois imprime 10.