【问题标题】:Convert repeated code into a loop将重复的代码转换为循环
【发布时间】:2018-12-29 03:05:52
【问题描述】:

我有一个运行 DD-WRT 的路由器,它有一个启动脚本,用于在某些端口上的 LAN 请求时唤醒我的计算机。我找到了这个 shell 脚本 here 并将其更改为允许在多个端口上唤醒。我尝试了一个 for 循环,这样我就不必重复任何代码,但这不起作用。唯一有效的是:

#!/bin/sh
#Enable JFFS2 and place script in /jffs/ then run on startup in web interface.
#You can check the log from http://192.168.1.1/user/wol.html
INTERVAL=1
PINGTIME=1
OLD=""
PORTPLEX=32400
PORTFTPCTRL=20
PORTFTPDATA=21
PORTRDP=3389
WOLPORT=9
TARGET=192.168.1.8
BROADCAST=192.168.1.255
MAC=aa:bb:cc:dd:ee:ff
WOL=/usr/sbin/wol
LOGFILE="/tmp/www/wol.html"
echo "<meta http-equiv=\"refresh\" content=\"10\">" > $LOGFILE
echo "["`date`"] AUTO WOL Script started. <br>" >> $LOGFILE

while sleep $INTERVAL;do

NEW=`dmesg | awk '/ACCEPT/ && /DST='"$TARGET"'/ && /DPT='"$PORTPLEX"'/ {print }' | tail -1`
SRC=`dmesg | awk -F'[=| ]' '/ACCEPT/ && /DST='"$TARGET"'/ && /DPT='"$PORTPLEX"'/ {print $7}' | tail -1`
LINE=`dmesg | awk '/ACCEPT/ && /DST='"$TARGET"'/ && /DPT='"$PORTPLEX"'/'`
if [ "$NEW" != "" -a "$NEW" != "$OLD" ]; then
   if ping -qw $PINGTIME $TARGET >/dev/null; then
      echo "NOWAKE $TARGET was accessed by $SRC and is already alive at" `date` "<br>">> $LOGFILE
   else
      echo "WAKE $SRC causes wake on lan at" `date` "<br>">> $LOGFILE
      $WOL -i $BROADCAST -p $WOLPORT $MAC >> $LOGFILE
      echo "<br>" >> $LOGFILE
      sleep 1
   fi
   OLD=$NEW
fi

NEW=`dmesg | awk '/ACCEPT/ && /DST='"$TARGET"'/ && /DPT='"$PORTFTPCTRL"'/ {print }' | tail -1`
SRC=`dmesg | awk -F'[=| ]' '/ACCEPT/ && /DST='"$TARGET"'/ && /DPT='"$PORTFTPCTRL"'/ {print $7}' | tail -1`
LINE=`dmesg | awk '/ACCEPT/ && /DST='"$TARGET"'/ && /DPT='"$PORTFTPCTRL"'/'`
if [ "$NEW" != "" -a "$NEW" != "$OLD" ]; then
   if ping -qw $PINGTIME $TARGET >/dev/null; then
      echo "NOWAKE $TARGET was accessed by $SRC and is already alive at" `date` "<br>">> $LOGFILE
   else
      echo "WAKE $SRC causes wake on lan at" `date` "<br>">> $LOGFILE
      $WOL -i $BROADCAST -p $WOLPORT $MAC >> $LOGFILE
      echo "<br>" >> $LOGFILE
      sleep 1
   fi
   OLD=$NEW
fi

NEW=`dmesg | awk '/ACCEPT/ && /DST='"$TARGET"'/ && /DPT='"$PORTFTPDATA"'/ {print }' | tail -1`
SRC=`dmesg | awk -F'[=| ]' '/ACCEPT/ && /DST='"$TARGET"'/ && /DPT='"$PORTFTPDATA"'/ {print $7}' | tail -1`
LINE=`dmesg | awk '/ACCEPT/ && /DST='"$TARGET"'/ && /DPT='"$PORTFTPDATA"'/'`
if [ "$NEW" != "" -a "$NEW" != "$OLD" ]; then
   if ping -qw $PINGTIME $TARGET >/dev/null; then
      echo "NOWAKE $TARGET was accessed by $SRC and is already alive at" `date` "<br>">> $LOGFILE
   else
      echo "WAKE $SRC causes wake on lan at" `date` "<br>">> $LOGFILE
      $WOL -i $BROADCAST -p $WOLPORT $MAC >> $LOGFILE
      echo "<br>" >> $LOGFILE
      sleep 1
   fi
   OLD=$NEW
fi

NEW=`dmesg | awk '/ACCEPT/ && /DST='"$TARGET"'/ && /DPT='"$PORTRDP"'/ {print }' | tail -1`
SRC=`dmesg | awk -F'[=| ]' '/ACCEPT/ && /DST='"$TARGET"'/ && /DPT='"$PORTRDP"'/ {print $7}' | tail -1`
LINE=`dmesg | awk '/ACCEPT/ && /DST='"$TARGET"'/ && /DPT='"$PORTRDP"'/'`
if [ "$NEW" != "" -a "$NEW" != "$OLD" ]; then
   if ping -qw $PINGTIME $TARGET >/dev/null; then
      echo "NOWAKE $TARGET was accessed by $SRC and is already alive at" `date` "<br>">> $LOGFILE
   else
      echo "WAKE $SRC causes wake on lan at" `date` "<br>">> $LOGFILE
      $WOL -i $BROADCAST -p $WOLPORT $MAC >> $LOGFILE
      echo "<br>" >> $LOGFILE
      sleep 1
   fi
   OLD=$NEW
fi

done

我猜是 (1) 我不太了解 for 循环在 bash 中是如何工作的,或者 (2) DD-WRT 的 shell 脚本与其他版本的 Linux 不同,或者两者兼而有之。

如何将这部分代码转换为在每个端口上循环的 for 循环中执行?

NEW=`dmesg | awk '/ACCEPT/ && /DST='"$TARGET"'/ && /DPT='"$PORT"'/ {print }' | tail -1`
SRC=`dmesg | awk -F'[=| ]' '/ACCEPT/ && /DST='"$TARGET"'/ && /DPT='"$PORT"'/ {print $7}' | tail -1`
LINE=`dmesg | awk '/ACCEPT/ && /DST='"$TARGET"'/ && /DPT='"$PORT"'/'`
if [ "$NEW" != "" -a "$NEW" != "$OLD" ]; then
   if ping -qw $PINGTIME $TARGET >/dev/null; then
      echo "NOWAKE $TARGET was accessed by $SRC and is already alive at" `date` "<br>">> $LOGFILE
   else
      echo "WAKE $SRC causes wake on lan at" `date` "<br>">> $LOGFILE
      $WOL -i $BROADCAST -p $WOLPORT $MAC >> $LOGFILE
      echo "<br>" >> $LOGFILE
      sleep 1
   fi
   OLD=$NEW
fi

谢谢!

【问题讨论】:

  • 您能否说明每个重复代码块之间有哪些变化?将它们分解为变量并将该代码放入函数中,将变量作为参数传递。这会将代码减少为一系列函数调用。然后引入循环重复函数调用。
  • @cdarke 谢谢,我删除了bash 标签。嗯,唯一的区别在于前三行,我将哪个变量用于 $PORT。
  • @cdarke,我是否正确地假设循环中的函数与 Andre Gelinas 的答案相同?
  • 没有。该函数将在循环外声明。函数 call 将在循环内 - 只有一行。但我并不是说@AndreGelinas 错了,它只是一种不同的风格和方法。

标签: shell sh wake-on-lan dd-wrt


【解决方案1】:

你试过了吗? :

for PORT in $PORTPLEX $PORTFTPCTRL $PORTFTPDATA $PORTRDP; do
            NEW=`dmesg | awk '/ACCEPT/ && /DST='"$TARGET"'/ && /DPT='"$PORT"'/ {print }' | tail -1`
    SRC=`dmesg | awk -F'[=| ]' '/ACCEPT/ && /DST='"$TARGET"'/ && /DPT='"$PORT"'/ {print $7}' | tail -1`
    LINE=`dmesg | awk '/ACCEPT/ && /DST='"$TARGET"'/ && /DPT='"$PORT"'/'`
    if [ "$NEW" != "" -a "$NEW" != "$OLD" ]; then
       if ping -qw $PINGTIME $TARGET >/dev/null; then
          echo "NOWAKE $TARGET was accessed by $SRC and is already alive at" `date` "<br>">> $LOGFILE
       else
          echo "WAKE $SRC causes wake on lan at" `date` "<br>">> $LOGFILE
          $WOL -i $BROADCAST -p $WOLPORT $MAC >> $LOGFILE
          echo "<br>" >> $LOGFILE
          sleep 1
       fi
       OLD=$NEW
    fi
done

【讨论】:

  • 是的,这就是我最初尝试的方法,但它没有工作......看起来应该,但我想知道 DD-WRT 是否只是不喜欢 for-loops?值得怀疑,但谁知道呢。
  • 更正:最初,我将for PORT in $PORTPLEX $PORTFTPCTRL $PORTFTPDATA $PORTRDP 然后do 放在下一行。因此,我的代码中的不同之处在于 PORT 全部大写,do 在换行符上。这有什么不同吗?
  • 不...我的错误,抱歉...“port”应该是“PORT”,因为您使用的是 $PORT。我已经进行了相应的编辑。不,不应该对“做”有太大影响,这就是我的写作方式。
  • 啊,好的,感谢您的澄清。我想知道为什么它不起作用呢?也许我会看一些更多以 DD-WRT 为中心的帖子,看看是否有任何发现。
  • 您可以做的是在 if/else/fi 之前插入一些 echo 以查看 3 个变量中的真正内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-22
  • 1970-01-01
  • 2017-12-31
  • 2014-03-12
  • 1970-01-01
  • 1970-01-01
  • 2020-10-24
相关资源
最近更新 更多