Общие сведения о синтаксисе $

На основе рецепта @Chris Snow. Я сделал несколько улучшений:

  • проверка схемы http (она поддерживает только http)
  • проверка ответа http (проверка строки состояния ответа и разделение заголовка и тела строкой '\r\n', а не 'Connection: close', которая иногда не соответствует действительности)
  • ошибка на не-200 коде (важно скачивать файлы из интернета)

Вот код:

function __wget() {
    : ${DEBUG:=0}
    local URL=$1
    local tag="Connection: close"

    if [ -z "${URL}" ]; then
        printf "Usage: %s \"URL\" [e.g.: %s http://www.google.com/]" \
               "${FUNCNAME[0]}" "${FUNCNAME[0]}"
        return 1;
    fi  
    read proto server path <<<$(echo ${URL//// })
    local SCHEME=${proto//:*}
    local PATH=/${path// //} 
    local HOST=${server//:*}
    local PORT=${server//*:}
    if [[ "$SCHEME" != "http" ]]; then
        printf "sorry, %s only support http\n" "${FUNCNAME[0]}"
        return 1
    fi  
    [[ x"${HOST}" == x"${PORT}" ]] && PORT=80
    [[ $DEBUG -eq 1 ]] && echo "SCHEME=$SCHEME" >&2
    [[ $DEBUG -eq 1 ]] && echo "HOST=$HOST" >&2
    [[ $DEBUG -eq 1 ]] && echo "PORT=$PORT" >&2
    [[ $DEBUG -eq 1 ]] && echo "PATH=$PATH" >&2

    exec 3<>/dev/tcp/${HOST}/$PORT
    if [ $? -ne 0 ]; then
        return $?
    fi  
    echo -en "GET ${PATH} HTTP/1.1\r\nHost: ${HOST}\r\n${tag}\r\n\r\n" >&3
    if [ $? -ne 0 ]; then
        return $?
    fi  
    # 0: at begin, before reading http response
    # 1: reading header
    # 2: reading body
    local state=0
    local num=0
    local code=0
    while read line; do
        num=$(($num + 1))
        # check http code
        if [ $state -eq 0 ]; then
            if [ $num -eq 1 ]; then
                if [[ $line =~ ^HTTP/1\.[01][[:space:]]([0-9]{3}).*$ ]]; then
                    code="${BASH_REMATCH[1]}"
                    if [[ "$code" != "200" ]]; then
                        printf "failed to wget '%s', code is not 200 (%s)\n" "$URL" "$code"
                        exec 3>&-
                        return 1
                    fi
                    state=1
                else
                    printf "invalid http response from '%s'" "$URL"
                    exec 3>&-
                    return 1
                fi
            fi
        elif [ $state -eq 1 ]; then
            if [[ "$line" == $'\r' ]]; then
                # found "\r\n"
                state=2
            fi
        elif [ $state -eq 2 ]; then
            # redirect body to stdout
            # TODO: any way to pipe data directly to stdout?
            echo "$line"
        fi
    done <&3
    exec 3>&-
}
0
21.08.2018, 02:54
1 ответ

Чтобы напечатать или присвоить переменную, когда у вас нет преимущества завершающего пробела, вы можете использовать ${}для расширения параметра вместо $...

echo "12${three}45"

Для ваших целей это должно подойти, и это, вероятно, наиболее часто используемый подход. Также обратите внимание, что echo "12$three"будет работать нормально. Конечный символ — вот что важно. Это должен быть недопустимый символ в имени переменной. Тем не менее, использование echo "12${three}"не повредит, и я думаю, что это улучшит читаемость.

Иногда вместо этого вы можете увидеть нечто подобное...

echo "12"$three"45"

Обычно я бы этого избегал. В качестве альтернативы есть printf...

printf "12%d45\n" "$three"

Подробнее см. man printf, так как доступно множество форматов.

5
28.01.2020, 02:16

Теги

Похожие вопросы