Entenda porque um script bash não está executando main?

1

Eu fiz um clone de Zcash :

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

Estou tentando executar o fetch-params.sh no OS X e Solaris. É um script do Linux, por isso precisa de um pouco de mensagens. Abaixo está o diff imediato; e o script completo com alterações está no final da pergunta.

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

O problema que estou tendo é main não está sendo executado. O script sai silenciosamente após o 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$ 

Aqui está a coisa estranha ... Isso acontece no OS X e no Solaris. E se eu definir a alteração IS_SOLARIS=$(uname -s | grep -i -c sunos) para IS_SOLARIS=0 no OS X, então funciona. Ou se eu comentar em set -eu , então funciona. Eu nunca usei set -eu antes, mas eu não entendo sua falha [possível] dada a explicação em Quando usar o set -e .

O OS X fornece GNU bash, version 3.2.53 ; enquanto o Solaris 11 fornece GNU bash, version 4.1.17 .

Por favor, perdoe minha ignorância ... Por que o teste de IS_DARWIN e IS_SOLARIS faz o script morrer? Por que não está executando main?

Script totalmente modificado

#!/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
    
por jww 09.11.2016 / 19:26

2 respostas

3

Você pode simplesmente usar o padrão de Bash correspondente dessa forma.

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

Este é um teste estendido embutido no Bash. Para reduzir as chamadas para uname, salve o valor em uma variável.

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

Isso pode ser ainda mais simplificado como:

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

Ou como:

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

Ou mais simples

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

Exemplo executado a partir do Solaris (SunOS).

-bash-3.2$ uname
SunOS
-bash-3.2$ uname=$(uname | tr [A-Z] [a-z])
-bash-3.2$ [[ $uname =~ sunos ]];  IS_SOLARIS=$?; echo $IS_SOLARIS
0

-bash-3.2$ uname
SunOS
-bash-3.2$ uname=$(uname)
-bash-3.2$ [[ $uname =~ [Ss]un[Oo][Ss] ]];  IS_SOLARIS=$?; echo $IS_SOLARIS
0

-bash-3.2$ uname
SunOS
-bash-3.2$ uname=$(uname)
-bash-3.2$ [[ $uname =~ SunOS ]];  IS_SOLARIS=$?; echo $IS_SOLARIS
0
-bash-3.2$

-bash-3.2$ uname
SunOS
-bash-3.2$ [[ $(uname) =~ SunOS ]];  IS_SOLARIS=$?; echo $IS_SOLARIS
0
-bash-3.2$
    
por 10.11.2016 / 02:03
1

$ 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.

EDIT: espero que isso deixa claro. Eu sei que é uma surpresa se você não estivesse procurando por esse comportamento.

Isso pode ser verificado consultando-se o padrão POSIX secreto (seriamente, eles obscurecem um pouco a página esperando que mais pessoas comprem versões impressas).

link

EXIT STATUS

The following exit values shall be returned:

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

exemplo de solução

Apesar de não tentar detectar quando "ocorreu um erro":

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