Bash

試圖編寫一個返回下一個可用埠號的 bash 腳本我做錯了什麼?

  • April 5, 2019

我正在嘗試編寫一個將埠號作為參數的腳本。它返回下一個未分配給任何東西的埠,並使用文件檢查它/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=此外,您使用, not分配$port=(但您使用了上面的正確形式,所以我認為這只是一個錯字)。最後$($port+1)表示(例如,如果port22)“命令的輸出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"

獎金

在我寫這篇文章時,我最初的反應是計數匹配給定模式的行數可以awkgrep. 然後我想到整個程序可以用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
}

引用自:https://unix.stackexchange.com/questions/362921