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.
dc
vez em quando para mantê-lo alerta.dc
é um animal instável, mas pode ser apenas o utilitário comum mais rápido e estranhamente capaz em qualquer sistema Unix. Quando emparelhado,sed
ele pode fazer algumas coisas extraordinárias.dd
Ultimamente, tenho brincado com ele para poder substituir a monstruosidade que éreadline
. Aqui está uma pequena amostra de algumas coisas que eu tenho feito. Fazer umrev
indc
é quase brincadeira de criança.[string]P91P93P[string]P
. Portanto, tenho um pouco desed
você que pode achar útil: osed 's/[][]/]P93]&[1P[/g;s/[]3][]][[][1[]//g'
que sempre deve substituir os quadrados corretamente por um colchete de corda, depois aP
, o valor ascii decimal do quadrado e outroP
; depois, um[
colchete aberto para continuar a sequência. Não sei se você mexeu comdc
os recursos de conversão numérica / sequência de caracteres w / , mas - especialmente quando combinados comod
-, pode ser bastante divertido.Se você sabe que está lidando com dois números inteiros
a
eb
, essas expansões aritméticas simples do shell usando o operador ternário são suficientes para fornecer o máximo numérico:e min numérico:
Por exemplo
Aqui está um script de shell demonstrando isso:
fonte
max=$(( a >= b ? a : b ))
, mas o resultado é totalmente o mesmo - se a e b são iguais, não importa realmente qual é o retorno. É isso que você está perguntando?if (( a >= b )); then echo a is greater than or equal to b; fi
- é isso que você está pedindo? (note o uso de(( ))
aqui em vez de$(( ))
)sort
ehead
pode fazer isso:fonte
O(n log(n))
enquanto uma implementação eficiente do max seriaO(n)
. É nosso pouco significadon=2
, no entanto, uma vez que a geração de dois processos é muito maior.numbers="1 4 3 5 7 1 10 21 8";
echo $numbers | tr ' ' "\n" | sort -rn | head -n 1
max=0; for x in $numbers ; do test $x -gt $max && max=$x ; done
Você pode definir uma biblioteca de funções matemáticas predefinidas
bc
e usá-las na linha de comando.Por exemplo, inclua o seguinte em um arquivo de texto como
~/MyExtensions.bc
:Agora você pode ligar
bc
por:Para sua informação, existem funções gratuitas da biblioteca matemática , disponíveis on-line.
Usando esse arquivo, você pode calcular facilmente funções mais complicadas, como
GCD
:fonte
bc
s é apenas umadc
interface para os dias de hoje, mesmo que o GNUbc
não seja mais assim (mas o GNUdc
e o GNUbc
compartilham uma quantidade prodigiosa de sua base de código) . De qualquer forma, esta pode ser a melhor resposta aqui.bc
, imediatamente antes da chamada da função. No segundo arquivo necessário então :)Tempo demais para um comentário:
Embora você possa fazer essas coisas, por exemplo, com os combos
sort | head
ousort | tail
, parece um pouco abaixo do ideal em termos de manipulação de recursos e erros. No que diz respeito à execução, o combo significa gerar 2 processos apenas para verificar duas linhas. Isso parece ser um exagero.O problema mais sério é que, na maioria dos casos, você precisa saber que a entrada é sensata, ou seja, contém apenas números. A solução da @ glennjackmann resolve isso de maneira inteligente, pois
printf %d
deve vomitar não-inteiros. Também não funcionará com flutuadores (a menos que você altere o especificador de formato para%f
, onde você terá problemas de arredondamento).test $1 -gt $2
indicará se a comparação falhou ou não (o status de saída 2 significa que houve um erro durante o teste. Como esse geralmente é um shell embutido, não há processo adicional) - estamos falando da ordem de centenas execução vezes mais rápida, embora só funcione com números inteiros.Se você precisar comparar alguns números de ponto flutuante, uma opção interessante pode ser
bc
:seria o equivalente a
test $1 -gt $2
, e usando no shell:ainda é quase 2,5 vezes mais rápido que
printf | sort | head
(para dois números).Se você pode confiar nas extensões GNU
bc
, também pode usar aread()
função para ler os números diretamente nabc
assinatura.fonte
dc -e "${max}sm[z0=?dlm<Mps0lTx]ST[?z0!=Tq]S?[s0lm]SMlTx"
- oh, exceto quedc
faz a coisa toda (exceto o eco, embora pudesse) - ele lê stdin e imprime um$max
ou o número de entrada, dependendo de qual é menor. De qualquer forma, eu realmente não me importo de explicar e sua resposta é melhor do que eu ia escrever. Então, tenha meu voto positivo, por favor.dc
script explicado seria muito bom, o RPN não é visto com frequência nos dias de hoje.dc
puder fazer a E / S por si só, seria ainda mais elegante do que.Para obter o maior valor de $ a e $ b, use o seguinte:
Mas você precisa de algo em torno disso, provavelmente não pretende executar o número; portanto, para exibir o maior valor dos dois, use "eco"
O item acima se encaixa perfeitamente em uma função shell, por exemplo
Para atribuir o maior dos dois à variável, use esta versão modificada:
ou use a função definida:
A variação da função também oferece a oportunidade de adicionar uma verificação de erro de entrada ordenadamente.
Para retornar o máximo de dois números decimais / ponto flutuante, você pode usar
awk
EDIT: Usando esta técnica, você pode criar uma função de "limite" que opera de maneira inversa, conforme sua edição / nota. Esta função retornará o menor dos dois, por exemplo:
Eu gosto de colocar funções utilitárias em um arquivo separado, chamá-lo
myprogram.funcs
e usá-lo em um script da seguinte maneira:FWIW, isso ainda faz o que você fez, e sua versão, embora seja mais detalhada, é igualmente eficiente.
A forma mais compacta não é realmente melhor, mas evita a confusão de seus scripts. Se você tem muitas construções simples de se-então-outro-fi, o script se expande rapidamente.
Se você deseja reutilizar a verificação de números maiores / menores várias vezes em um único script, coloque-a em uma função. O formato da função facilita a depuração e a reutilização e permite substituir facilmente essa parte do script, por exemplo, por um comando awk para poder manipular números decimais não inteiros.
Se for um caso de uso único, basta codificá-lo em linha.
fonte
Você pode definir uma função como
Chame como
maxnum 54 42
e ecoa54
. Você pode adicionar informações de validação dentro da função (como dois argumentos ou números como argumentos), se desejar.fonte
function maxnum {
paramaxnum() {
e funcionará por muito mais conchas.Em um script de shell, existe uma maneira de usar qualquer método estático público Java (e, por exemplo, Math.min () ). Do bash no Linux:
Isso requer o Java Shell Bridge https://sourceforge.net/projects/jsbridge/
Muito rápido, porque as chamadas de método são canalizadas internamente ; nenhum processo é necessário.
fonte
A maioria das pessoas simplesmente faz
sort -n input | head -n1
(ou segue), é bom o suficiente para a maioria das situações de script. No entanto, isso é um pouco desajeitado se você tiver números em uma linha em vez de em uma coluna - precisará imprimi-lo em um formato adequado (tr ' ' '\n'
ou algo semelhante).Os shells não são exatamente ideais para processamento numérico, mas você pode facilmente inserir outros programas que são melhores nele. Dependendo da sua preferência, você liga no máximo
dc
(um pouco ofuscado, mas se você sabe o que está fazendo, tudo bem - veja a resposta do mikeserv), ouawk 'NR==1{max=$1} {if($1>max){max=$1}} END { print max }'
. Ou possivelmenteperl
oupython
se você preferir. Uma solução (se você estiver disposto a instalar e usar software menos conhecido) seriaised
(especialmente se seus dados estiverem em uma única linha: você só precisa fazê-loised --l input.dat 'max$1'
).Como você está pedindo dois números, tudo isso é um exagero. Isso deve ser suficiente:
fonte
sys.argv
:python2 -c 'import sys; print (max(sys.argv))' "$@"
sort + head
são um exagero, maspython
não são computados.python
porque é legal.python
fanático (ou porque não requer um garfo e um intérprete gigante adicional) . Ou talvez ambos.