試圖編寫一個返回下一個可用埠號的 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=
此外,您使用, not分配$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 }