概述

概述

我正在尝试编写一个以端口号作为参数的脚本。它返回下一个未分配给任何内容的端口,并使用文件检查它/etc/services。如果端口被占用(即在文档中列出),它会添加一个,然后重试。我似乎无法让这个脚本返回“found”的任何内容 - 它始终等于 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,这不是问题)

答案1

概述

这个脚本只有一些小错误,还有一些我会改变的风格。让我们逐行浏览一下原始内容:

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

奖金

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

减去数学部分,这里有一个快速而肮脏的 POC 来完成您想要的任务,但使用“if”语句代替“while”循环条件来实现您的逻辑。

#!/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 按字面意思解释,因此它的 grep 是字符串“$port/”而不是“80/”。修复:只需将单引号更改为双引号即可。

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

相关内容