明白为什么 bash 脚本不执行 main 吗?

明白为什么 bash 脚本不执行 main 吗?

我执行了一个克隆零币

$ git clone https://github.com/zcash/zcash.git
$ cd zcash/
$ git checkout v1.0.1
$ ./zcutil/fetch-params.sh

我正在尝试跑步fetch-params.sh在 OS X 和 Solaris 上。它是一个 Linux 脚本,因此需要一些消息传递。以下是直接差异;带有更改的完整脚本位于问题的末尾。

diff --git a/zcutil/fetch-params.sh b/zcutil/fetch-params.sh
index ac5327b..e2e9807 100755
--- a/zcutil/fetch-params.sh
+++ b/zcutil/fetch-params.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash

 set -eu

@@ -12,6 +12,9 @@ SPROUT_VKEY_URL="https://z.cash/downloads/$SPROUT_VKEY_NAME"
 SHA256CMD="$(command -v sha256sum || echo shasum)"
 SHA256ARGS="$(command -v sha256sum >/dev/null || echo '-a 256')"

+IS_DARWIN=$(uname -s | grep -i -c darwin)
+IS_SOLARIS=$(uname -s | grep -i -c sunos)
+
 function fetch_params {
     local url="$1"
     local output="$2"
@@ -45,13 +48,20 @@ EOF

 # Use flock to prevent parallel execution.
 function lock() {
-    local lockfile=/tmp/fetch_params.lock
-    # create lock file
-    eval "exec 200>/$lockfile"
-    # acquire the lock
-    flock -n 200 \
-        && return 0 \
-        || return 1
+   local lockfile="/tmp/fetch_params.lock"
+    if [[ ("$IS_SOLARIS" -ne "0" || "$IS_DARWIN" -ne "0") ]]; then
+        # http://unix.stackexchange.com/a/13025
+        mkdir "$lockfile" \
+            && return 0 \
+            || return 1
+    else
+        # create lock file
+        eval "exec 200>/$lockfile"
+        # acquire the lock
+        flock -n 200 \
+           && return 0 \
+           || return 1
+    fi
 }

 function exit_locked_error {
@@ -105,5 +115,11 @@ EOF
 }

 main
-rm -f /tmp/fetch_params.lock
+
+if [[ ("$IS_SOLARIS" -ne "0" || "$IS_DARWIN" -ne "0") ]]; then
+    rm -rf /tmp/fetch_params.lock
+else
+    rm -f /tmp/fetch_params.lock
+fi
+
 exit 0

我遇到的问题是main没有执行。脚本在以下内容后安静退出IS_SOLARIS=$(uname -s | grep -i -c sunos)

riemann:zcash$  bash -x ./zcutil/fetch-params.sh 
+ set -eu
...
++ uname -s
++ grep -i -c darwin
+ IS_DARWIN=1
++ uname -s
++ grep -i -c sunos
+ IS_SOLARIS=0
riemann:zcash$ 

奇怪的是......OS X 和 Solaris 上都会发生这种情况。如果我在 OS X 上将更改设置IS_SOLARIS=$(uname -s | grep -i -c sunos)IS_SOLARIS=0,那么它就会起作用。或者如果我注释掉它,set -eu它就会起作用。我从未使用过set -eu之前,但鉴于解释,我不明白它的[可能]失败何时使用 set -e

OS X 提供GNU bash, version 3.2.53;而 Solaris 11 则提供GNU bash, version 4.1.17.

请原谅我的无知...为什么测试IS_DARWINIS_SOLARIS导致脚本死掉?为什么不执行main?


完整修改的脚本

#!/usr/bin/env bash

set -eu

PARAMS_DIR="$HOME/.zcash-params"

SPROUT_PKEY_NAME='sprout-proving.key'
SPROUT_VKEY_NAME='sprout-verifying.key'
SPROUT_PKEY_URL="https://z.cash/downloads/$SPROUT_PKEY_NAME"
SPROUT_VKEY_URL="https://z.cash/downloads/$SPROUT_VKEY_NAME"

SHA256CMD="$(command -v sha256sum || echo shasum)"
SHA256ARGS="$(command -v sha256sum >/dev/null || echo '-a 256')"

IS_DARWIN=$(uname -s | grep -i -c darwin)
IS_SOLARIS=$(uname -s | grep -i -c sunos)

function fetch_params {
    local url="$1"
    local output="$2"
    local dlname="${output}.dl"
    local expectedhash="$3"

    if ! [ -f "$output" ]
    then
        echo "Retrieving: $url"
        wget \
            --progress=dot:giga \
            --output-document="$dlname" \
            --continue \
            --retry-connrefused --waitretry=3 --timeout=30 \
            "$url"

        "$SHA256CMD" $SHA256ARGS --check <<EOF
$expectedhash  $dlname
EOF

        # Check the exit code of the shasum command:
        CHECKSUM_RESULT=$?
        if [ $CHECKSUM_RESULT -eq 0 ]; then
            mv -v "$dlname" "$output"
        else
           echo "Failed to verify parameter checksums!"
           exit 1
        fi
    fi
}

# Use flock to prevent parallel execution.
function lock() {
    local lockfile="/tmp/fetch_params.lock"
    if [[ ("$IS_SOLARIS" -ne "0" || "$IS_DARWIN" -ne "0") ]]; then
        # http://unix.stackexchange.com/a/13025
        mkdir "$lockfile" \
            && return 0 \
            || return 1
    else
        # create lock file
        eval "exec 200>/$lockfile"
        # acquire the lock
        flock -n 200 \
           && return 0 \
           || return 1
    fi
}

function exit_locked_error {
    echo "Only one instance of fetch-params.sh can be run at a time." >&2
    exit 1
}

function main() {

    lock fetch-params.sh \
    || exit_locked_error

    cat <<EOF
Zcash - fetch-params.sh

This script will fetch the Zcash zkSNARK parameters and verify their
integrity with sha256sum.

If they already exist locally, it will exit now and do nothing else.
EOF

    # Now create PARAMS_DIR and insert a README if necessary:
    if ! [ -d "$PARAMS_DIR" ]
    then
        mkdir -p "$PARAMS_DIR"
        README_PATH="$PARAMS_DIR/README"
        cat >> "$README_PATH" <<EOF
This directory stores common Zcash zkSNARK parameters. Note that it is
distinct from the daemon's -datadir argument because the parameters are
large and may be shared across multiple distinct -datadir's such as when
setting up test networks.
EOF

        # This may be the first time the user's run this script, so give
        # them some info, especially about bandwidth usage:
        cat <<EOF
The parameters are currently just under 911MB in size, so plan accordingly
for your bandwidth constraints. If the files are already present and
have the correct sha256sum, no networking is used.

Creating params directory. For details about this directory, see:
$README_PATH

EOF
    fi

    cd "$PARAMS_DIR"

    fetch_params "$SPROUT_PKEY_URL" "$PARAMS_DIR/$SPROUT_PKEY_NAME" "8bc20a7f013b2b58970cddd2e7ea028975c88ae7ceb9259a5344a16bc2c0eef7"
    fetch_params "$SPROUT_VKEY_URL" "$PARAMS_DIR/$SPROUT_VKEY_NAME" "4bd498dae0aacfd8e98dc306338d017d9c08dd0918ead18172bd0aec2fc5df82"
}

main

if [[ ("$IS_SOLARIS" -ne "0" || "$IS_DARWIN" -ne "0") ]]; then
    rm -rf /tmp/fetch_params.lock
else
    rm -f /tmp/fetch_params.lock
fi

exit 0

答案1

您可以像这样使用 Bash 模式匹配。

[[ $(uname) = *[Dd]arwin* ]]; IS_DARWIN=$?
[[ $(uname) = *[Ss]un[Oo][Ss]* ]];  IS_SOLARIS=$?

这是 Bash 内置的扩展测试。为了减少对 uname 的调用,请将值保存到变量中。

uname=$(uname)
[[ $uname = *[Dd]arwin* ]]; IS_DARWIN=$?
[[ $uname = *[Ss]un[Oo][Ss]* ]];  IS_SOLARIS=$?

这可以进一步简化为:

uname=$(uname)
[[ $uname =~ [Dd]arwin ]]; IS_DARWIN=$?
[[ $uname =~ [Ss]un[Oo][Ss] ]];  IS_SOLARIS=$?

或者作为:

uname=$(uname | tr [A-Z] [a-z])
[[ $uname =~ darwin ]]; IS_DARWIN=$?
[[ $uname =~ sunos ]];  IS_SOLARIS=$?

或者最简单的

uname=$(uname)
[[ $uname =~ Darwin ]]; IS_DARWIN=$?
[[ $uname =~ SunOS ]];  IS_SOLARIS=$?

示例在 Solaris (SunOS) 上运行。

-bash-3.2$ uname
太阳操作系统
-bash-3.2$ uname=$(uname | tr [AZ] [az])
-bash-3.2$ [[ $uname =~ sunos ]]; IS_SOLARIS=$?;回显$IS_SOLARIS
0

-bash-3.2$ uname
太阳操作系统
-bash-3.2$ uname=$(uname)
-bash-3.2$ [[ $uname =~ [Ss]un[Oo][Ss] ]]; IS_SOLARIS=$?;回显$IS_SOLARIS
0

-bash-3.2$ uname
太阳操作系统
-bash-3.2$ uname=$(uname)
-bash-3.2$ [[ $uname =~ SunOS ]]; IS_SOLARIS=$?;回显$IS_SOLARIS
0
-bash-3.2$

-bash-3.2$ uname
太阳操作系统
-bash-3.2$ [[ $(uname) =~ SunOS ]]; IS_SOLARIS=$?;回显$IS_SOLARIS
0
-bash-3.2$

答案2

$ man grep

/EXIT

EXIT STATUS
   Normally the exit status is 0 if a line is selected, 1 if no lines were
   selected, and 2 if an error occurred.  However, if the -q or --quiet or
   --silent  is  used and a line is selected, the exit status is 0 even if
   an error occurred.

编辑:希望这能够清楚地表明这一点。我知道如果您没有寻找这种行为,那会让人感到惊讶。

这可以通过参考秘密 POSIX 标准来验证(说真的,他们稍微模糊了网页,希望更多的人购买印刷版)。

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/grep.html#tag_20_55_14

退出状态

The following exit values shall be returned:

 0
    One or more lines were selected.
 1
    No lines were selected.
>1
    An error occurred.

示例解决方案

尽管没有尝试检测“发生错误”的时间:

if (uname -s | grep -i darwin >/dev/null); then
  IS_DARWIN=1
fi

相关内容