【问题标题】:"If" "then" "else" and "return" command syntax"If" "then" "else" 和 "return" 命令语法
【发布时间】:2018-02-21 22:24:57
【问题描述】:

我是一名在焊接车间工作的管道安装工,并且需要音乐,因为商业广播非常重复。我去买了一个 RPI3 并使用 fm_transmitter 程序将 Raspian Stretch Lite 放在上面。我得到了足够长的 shell 脚本,收音机可以正常工作,但有时我会在短时间内再次播放一首歌。这只是偶然,因为 RANDOM_FILE 变量是从整个目录中选择的。我还获得了记录在文本文件中播放的每首歌曲的脚本。我想使用 tail 和 grep 在文本文件中搜索当前选择的 RANDOM_FILE 并检查它是否存在于日志中最后 X 首歌曲中。如果 RANDOM_FILE 存在于 grep 命令中,我希望脚本在定义新的 RANDOM_FILE 的顶部重新启动。如果它不存在,我希望脚本继续运行,允许 RANDOM_FILE 通过 fm_transmitter 程序播放。

我还希望有人检查定义 RANDOM_FILE 的字符串实际上是否真正随机且正确。

以下是当前形式的脚本。我相信我已经接近了,但是在某个地方出错了,因为我仍然会重复。我需要有关“if”“then”“else”和“return”命令的帮助。我希望这是一个快速简便的解决方案。

提前感谢所有花时间帮助我的人。

#!/bin/bash

while :
do
    files=(/home/pi/music/*.wav)
    RANDOM_FILE="${files[RANDOM % ${#files[@]}]}"

        if tail -n 25 /home/pi/transmit_log.txt | grep "$RANDOM_FILE" = true ; then
            echo -e "---SONG_SKIPPED---" >> /home/pi/transmit_log.txt ; return 7
        else

#            [ tail -n 25 /home/pi/transmit_log.txt | grep "$RANDOM_FILE" = false ] ; then
            return 22
        fi

    echo -e "$RANDOM_FILE" >> /home/pi/transmit_log.txt
    sox -v 3 "$RANDOM_FILE" -r 44100 -c 1 -b 16 -t wav - | sudo ./fm_transmitter -f 91.7 -
    sleep .5


done

【问题讨论】:

  • 有点不清楚你的问题是什么,或者有很多相互关联的问题很难回答。不幸的是,Stack Overflow 是一个糟糕的教程网站,而且是一个更糟糕的调试器。你会做得更好,只是试一试,然后提出一个具体的问题。但是,需要说一件事:有“随机”,也有“随机”。计算机,尤其是小型计算机,在真正的随机性方面很糟糕,所以你能得到的最好的就是伪随机。
  • 话虽如此,有一些技术可以改善明显的随机性——通常是通过重新播种“随机数生成器”等。你在这里做的很好——如果我们有,就忽略结果在最近 N 次播放中看到相同的选择并再次尝试。
  • 好的,我认为您的主要问题是“为什么即使我忽略了与最近 25 次播放匹配的选项,我也会重复播放歌曲”?这是调试开始使用的地方。您已经在记录跳过和播放,因此请检查播放日志并查看您的感知是否与现实相符。你真的有重复吗?你有任何跳过吗?这自然会导致询问跳过歌曲的行是否在做你认为它在做的事情。我想你的答案可能在这里:unix.stackexchange.com/a/48536/156990
  • 也有用:*.com/q/8988824/1531971(查看答案,尤其是关于使用/dev/urandom

标签: bash if-statement


【解决方案1】:

我不相信你可以像这样在 if/else 语句中返回。 Return 在函数中用于返回值。 相反,您可以使用 continue ,它将跳过循环的下一次迭代(并像 codeforester 建议的那样修复测试):

#!/bin/bash
while :
do
    files=(/home/pi/music/*.wav)
    RANDOM_FILE="${files[RANDOM % ${#files[@]}]}"

    if tail -n 25 /home/pi/transmit_log.txt | grep -q "$RANDOM_FILE" ; then
        echo "---SONG_SKIPPED---" >> /home/pi/transmit_log.txt
        continue
    fi

    echo "$RANDOM_FILE" >> /home/pi/transmit_log.txt
    sox -v 3 "$RANDOM_FILE" -r 44100 -c 1 -b 16 -t wav - | sudo ./fm_transmitter -f 91.7 -
    sleep .5
done

或者,最好将测试拆分如下所示,以使 if 条件更小且更具可读性:

already_played=$( tail -n 25 /home/pi/transmit_log.txt | grep "$RANDOM_FILE" )
if [ ! -z "$aldeady_played" ]; then
    ...
fi

【讨论】:

  • 我想不出在没有-e 的情况下echo -e 会比echo 更正确的任何场景。 (顺便说一句,当您确实需要扩展反斜杠转义序列的行为时,the POSIX spec for echo 明确建议改用printf %b;请参阅应用程序使用部分)。
  • TheEmbeddedLab:我尝试了您对脚本的第一次编辑,现在它似乎可以工作了。非常感谢。
  • @CharlesDuffy 你说得对,我是基于 TheChopsCronicles 最初发布的代码,并没有注意到 -e。我将编辑我的答案。
【解决方案2】:

问题出在此声明中:

if tail -n 25 /home/pi/transmit_log.txt | grep "$RANDOM_FILE" = true; then ...

正确的方法是:

if tail -n 25 /home/pi/transmit_log.txt | grep -q "$RANDOM_FILE"; then ...

在您的构造中,= true 将作为参数传递给grep。这不是你想要的,对吧?如果找到模式,grep -q 将返回 0(或 true),我相信这就是您想要的。

【讨论】:

  • 好的,----SONG_SKIPPED---- 文本现在显示在transmit_log.txt 文件中,但检查日志显示正在播放的歌曲已在之前播放过200 行的传输日志.txt。 (我将tail命令编辑为:tail -n 200 以增加必须跳过一首歌的机会)是不是脚本没有回到脚本的开头重新开始?该脚本仍然允许播放所谓的跳过的文件并将 ----SONG_SKIPPED---- 添加到日志中?