Что я делаю неправильно, пытаясь написать сценарий bash, который возвращает номер следующего доступного порта?

Способ использования одной команды - удаление -тип , из команды. Тогда мы получим:

find /var/www/html/*/dir0/dir1/ ! -name 'he_IL.mo' -exec rm -f {} + 

Обратите внимание, что он не будет удалять каталоги и программные ссылки с именем he_IL.mo , но если все в порядке, используйте его.

1
20.05.2017, 13:56
2 ответа

Обзор

В этом скрипте всего несколько мелких ошибок, и я бы изменил несколько стилистических вещей. Давайте построчно пройдемся по оригиналу:

#!/bin/bash

port=$1

Типичный #! и простое присваивание, у нас хорошее начало.

found=$(cat /etc/services | grep -o '[[:space:]]$port/' | wc -l)

В этой строке есть небольшая проблема, которую можно не заметить на первый взгляд. Поскольку $port находится в сильных кавычках, '…$port', он не будет расширяться до своего значения. Вы можете использовать слабые кавычки вместо "…$port". Кроме того, здесь вам не нужен кошка. grep принимает имя файла в качестве аргумента, но если это не так, вы всегда можете использовать перенаправление (grep 'шаблон' < /etc/services). Кроме того, grep -c записывает количество совпадающих строк, поэтому wc -l здесь также избыточен.

while [ $found -ge 1 ]; do
    $port=$($port+1)
done

Цикл кажется почти в порядке. Вы захотите указать сущности в тесте на случай, если $found может оказаться пустым. Кроме того, вы назначаете с помощью port=, а не $port= (но вы использовали правильную форму выше, поэтому я предполагаю, что это была просто опечатка). Наконец, $($port+1) означает (например, если порт равен 22) «Вывод команды 22+1".Очевидно, вам нужен «Результат арифметического выражения 22+1», который очень похож на $(($port+1)).

echo "found: $found"
echo "port: $port"

С этими строками все в порядке.

Учитывая логику

Теперь, если вы сделаете все вышеперечисленные изменения, чтобы программа стала синтаксически правильной, она все равно не будет делать то, что вы хотите. Вы не указали «правильный» вывод, поэтому я предполагаю, что вы хотите:

found: <the number of occurrences of $1 in /etc/services>
port: <the next free port>

Если эти предположения неверны, дайте мне знать в комментариях, и я отредактирую соответствующим образом.

Сценарий как есть никогда не вернется, если данный порт действительно появляется в /etc/services, потому что вы никогда не обновляете found. Таким образом, вы можете подумать, что было бы разумно скопировать строку found=… в цикл, но это не так! Если вы это сделаете, то скрипт всегда будет возвращать found: 0. Я думаю, что лучше всего здесь создать функцию:

found () {
    grep -co "[[:space:]]$1/" /etc/services
}

, но теперь выходное значение этой функции может напрямую работать как условие. Вы захотите заглушить вывод, чтобы он не отображался вместе с вашим, и тогда вам больше не понадобятся флаги -co, но вам понадобятся -q:

while found "$port"; do

Затем, чтобы вернуть количество вхождений порта ввода, это будет

echo "found: $(found "$1")"

или вы можете использовать printf.

Собираем все воедино

Я думаю, что это сценарий, который вы пытались написать:

#!/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"

Бонус

Когда я писал это, моей первой реакцией было то, что подсчет строк, соответствующих заданному шаблону, может быть выполнен в awk, а также grep.Затем мне пришло в голову, что всю программу можно написать на awk. В качестве бонуса вот одна из его реализаций (хотя здесь я предполагаю, что /etc/services сортируется по номеру порта):

#!/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
}
2
27.01.2020, 23:45

За исключением математической части, вот быстрый и грязный POC для выполнения того, что вы собираетесь сделать, но с использованием оператора «if» вместо условий цикла «пока» для вашей логики.

#!/bin/bash

port=$1
echo $port | while read a; do
found=$(cat /etc/services | grep -Eo '[0-9]{1,5}/' | sed 's/^/ /' | grep ' '$a'/')
if [[ $found ]];
then echo port $a is being used
else echo port $a is not being used
fi
done

Редактировать: проблема возникла из-за переменной $found. одинарные кавычки в grep заставляют $port интерпретироваться буквально, поэтому он ищет строку Например, '$port/' вместо '80/'. исправить: просто измените одинарные кавычки на двойные кавычки.

found=$(cat /etc/services | grep -o "[[:space:]]$port/" | wc -l)

-1
27.01.2020, 23:45

Теги

Похожие вопросы