Visão geral
Existem apenas alguns pequenos erros com este script e algumas coisas estilísticas que eu mudaria. Vamos percorrer o original linha por linha:
#!/bin/bash
port=$1
Uma típica linha #!
e uma atribuição simples, começamos bem.
found=$(cat /etc/services | grep -o '[[:space:]]$port/' | wc -l)
Esta linha tem um pequeno problema que pode não ser percebido à primeira vista. Como $port
está em citações strongs , '…$port'
, ele não se expandirá para seu valor. Você vai querer usar aspas fracas , "…$port"
. Além disso, você realmente não precisa de cat
aqui. grep
usa um nome de arquivo como argumento, mas se não, você sempre pode usar o redirecionamento ( grep 'pattern' < /etc/services
). Além disso, grep -c
escreve uma contagem de linhas correspondentes, então wc -l
é redundante aqui também.
while [ $found -ge 1 ]; do
$port=$($port+1)
done
O loop parece quase bom. Você desejará citar as entidades no teste no caso de $found
poder estar vazio. Além disso, você atribui com port=
, não $port=
(mas usou o formulário correto acima, então presumo que seja apenas um erro de digitação). Finalmente $($port+1)
significa (se port
é 22
, por exemplo) "A saída do comando 22+1
". Claramente você quer "O resultado da expressão aritmética 22+1
", que é o mesmo $(($port+1))
.
echo "found: $found"
echo "port: $port"
Estas linhas estão bem como estão.
Considerando a lógica
Agora, se você fizer todas as alterações acima para que o programa esteja sintaticamente correto, ele ainda não fará o que você deseja. Você não lista uma saída "correta", então estou supondo que você queira:
found: <the number of occurrences of $1 in /etc/services>
port: <the next free port>
Se essas suposições estiverem incorretas, me avise nos comentários e eu os editarei de acordo.
O script como ele nunca retornará se a porta fornecida aparecer em /etc/services
, porque você nunca atualiza found
. Então você pode pensar que seria prudente copiar a linha found=…
para o loop, mas isso não é verdade! Se você fez isso, o script sempre retornará found: 0
. Acho que a melhor coisa a fazer aqui é criar uma função :
found () {
grep -co "[[:space:]]$1/" /etc/services
}
mas agora o valor de saída dessa função pode funcionar diretamente como uma condição. Você vai querer aquietar a saída para que ela não apareça junto com a sua e, em seguida, você não precisará mais dos sinalizadores -co
, mas desejará -q
:
while found "$port"; do
Em seguida, para retornar o número de ocorrências da porta de entrada, seria
echo "found: $(found "$1")"
ou você pode usar printf
.
Colocando tudo junto
Acho que este é o script que você estava tentando escrever:
#!/bin/sh
found () {
grep -q "[[:space:]]$1/" /etc/services
}
port=$1
while found "$port"; do
port=$(($port+1))
done
printf 'found: %d\nport %d\n' "$(found "$1")" "$port"
Bônus
Como eu estava escrevendo isso, minha reação inicial foi que as linhas de contagem correspondentes a um determinado padrão poderiam ser feitas em awk
, bem como grep
. Ocorreu-me então que todo o programa poderia ser escrito em awk
. Como um bônus, aqui está uma implementação disso (apesar de aqui eu assumir que /etc/services
é classificado pelo número da porta):
#!/usr/bin/awk -f
BEGIN {
FS = "[ \t/][ \t/]*"
ARGC = 2
PORT = ARGV[1]
OPORT = PORT
ARGV[1] = "/etc/services"
}
($2 == OPORT) {
FOUND = FOUND + 1
}
(NEXT == 0 && NR > 1 && $2 > PORT) {
NEXT = ($2 > PORT + 1) ? PORT + 1 : NEXT
PORT = $2
}
END {
printf "found: %d\nport: %d\n", FOUND, (FOUND == 0) ? OPORT : NEXT
}