Intereting Posts
Изменение Debian и системных часов? Networkmanager заполняет resolv.conf неправильной информацией, которая приводит к неудачным DNS-запросам Сокращение Apache-спама Путаница в изменении смысла аргументов и опций, есть ли официальное стандартное определение? Как выполнить программу в gnome и заставить ее использовать другую тему gtk, отличную от стандартной? Почему команда echo не работает с командой? исключать пустые и скрытые файлы при архивировании Драйвер для беспроводной сетевой карты Intel 2200BG Отрицательный взгляд на несколько строк Ошибка sshfs: сброс соединения с помощью сверстника fstrim, похоже, не обрезает раздел, который использует lvm и dm-crypt При настройке SFTP между * nix-серверами, является ли это обычное рукопожатие необязательным? Попытка SSH на сервер и получение key_load_public: Нет такой ошибки в файле или каталоге Как запрограммировать передачу сигнала разрыва (Magic SysRq) через последовательный терминал Как вы остановите «wget» после того, как он получит 404?

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

Я пытаюсь написать сценарий, который принимает номер порта в качестве аргумента. Он возвращает следующий порт, который не назначен ни на что, и проверяет его с помощью файла /etc/services . Если порт взят (т.е. указан в документе), он добавляет один, а затем повторяет попытку. Я не могу заставить этот скрипт возвращать что-либо для «найденного» – он всегда равен 0, поэтому я никогда не вхожу в цикл while. Что я делаю не так?

 #!/bin/bash port=$1 found=$(cat /etc/services | grep -o '[[:space:]]$port/' | wc -l) while [ $found -ge 1 ]; do $port=$($port+1) #done echo "found: $found" echo "port: $port" 

(игнорируйте комментарий перед done , это не проблема)

обзор

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

 #!/bin/bash port=$1 

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

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

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

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

Цикл кажется почти прекрасным. Вы захотите процитировать объекты в тесте, если $found может быть пустым. Кроме того, вы назначаете с помощью port= , а не $port= (но вы использовали правильную форму выше, поэтому я предполагаю, что это была только опечатка). Наконец, $($port+1) означает (если, например, port 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 } 

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

 #!/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 интерпретированы буквально, поэтому его grepping для строки '$ port /' вместо '80 /', например. fix: просто измените одинарные кавычки на двойные кавычки.

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

Надеюсь это поможет