[bash] curl 명령을 위해 데이터를 urlencode하는 방법은 무엇입니까?

테스트를 위해 매개 변수를 사용하고 curl을 통해 웹 사이트로 보내는 bash 스크립트를 작성하려고합니다. 특수 문자가 올바르게 처리되도록 값을 URL 인코딩해야합니다. 가장 좋은 방법은 무엇입니까?

지금까지 내 기본 스크립트는 다음과 같습니다.

#!/bin/bash
host=${1:?'bad host'}
value=$2
shift
shift
curl -v -d "param=${value}" http://${host}/somepath $@



답변

사용 curl --data-urlencode; 부터 man curl:

이것은 --dataURL 인코딩을 수행한다는 점을 제외 하고 다른 옵션과 마찬가지로 데이터를 게시합니다 . CGI 규격을 준수하려면 <data>부품 이름과 구분 기호 및 내용 사양으로 시작해야합니다.

사용법 예 :

curl \
    --data-urlencode "paramName=value" \
    --data-urlencode "secondParam=value" \
    http://example.com

자세한 내용 은 매뉴얼 페이지 를 참조하십시오.

curl 7.18.0 이상 (2008 년 1 월 릴리스) 이 필요합니다 . 사용 curl -V중인 버전을 확인하는 데 사용하십시오 .

쿼리 문자열을 인코딩 할 수도 있습니다 .

curl -G \
    --data-urlencode "p1=value 1" \
    --data-urlencode "p2=value 2" \
    http://example.com
    # http://example.com?p1=value%201&p2=value%202


답변

다음은 순수한 BASH 답변입니다.

rawurlencode() {
  local string="${1}"
  local strlen=${#string}
  local encoded=""
  local pos c o

  for (( pos=0 ; pos<strlen ; pos++ )); do
     c=${string:$pos:1}
     case "$c" in
        [-_.~a-zA-Z0-9] ) o="${c}" ;;
        * )               printf -v o '%%%02x' "'$c"
     esac
     encoded+="${o}"
  done
  echo "${encoded}"    # You can either set a return variable (FASTER) 
  REPLY="${encoded}"   #+or echo the result (EASIER)... or both... :p
}

두 가지 방법으로 사용할 수 있습니다.

easier:  echo http://url/q?=$( rawurlencode "$args" )
faster:  rawurlencode "$args"; echo http://url/q?${REPLY}

[편집]

일치하는 rawurldecode () 함수는 다음과 같습니다.

# Returns a string in which the sequences with percent (%) signs followed by
# two hex digits have been replaced with literal characters.
rawurldecode() {

  # This is perhaps a risky gambit, but since all escape characters must be
  # encoded, we can replace %NN with \xNN and pass the lot to printf -b, which
  # will decode hex for us

  printf -v REPLY '%b' "${1//%/\\x}" # You can either set a return variable (FASTER)

  echo "${REPLY}"  #+or echo the result (EASIER)... or both... :p
}

일치 세트를 사용하여 간단한 테스트를 수행 할 수 있습니다.

$ diff rawurlencode.inc.sh \
        <( rawurldecode "$( rawurlencode "$( cat rawurlencode.inc.sh )" )" ) \
        && echo Matched

Output: Matched

그리고 정말로 외부 도구가 필요하다고 생각한다면 (더 빨리 가고, 바이너리 파일 등을 할 수 있습니다 …) OpenWRT 라우터에서 이것을 찾았습니다 …

replace_value=$(echo $replace_value | sed -f /usr/lib/ddns/url_escape.sed)

url_escape.sed는 다음 규칙을 포함하는 파일입니다.

# sed url escaping
s:%:%25:g
s: :%20:g
s:<:%3C:g
s:>:%3E:g
s:#:%23:g
s:{:%7B:g
s:}:%7D:g
s:|:%7C:g
s:\\:%5C:g
s:\^:%5E:g
s:~:%7E:g
s:\[:%5B:g
s:\]:%5D:g
s:`:%60:g
s:;:%3B:g
s:/:%2F:g
s:?:%3F:g
s^:^%3A^g
s:@:%40:g
s:=:%3D:g
s:&:%26:g
s:\$:%24:g
s:\!:%21:g
s:\*:%2A:g


답변

bash 스크립트의 두 번째 줄에서 Perl의 URI::Escape모듈과 uri_escape기능을 사용하십시오 .

...

value="$(perl -MURI::Escape -e 'print uri_escape($ARGV[0]);' "$2")"
...

편집 : 주석에서 Chris Johnsen이 제안한대로 인용 문제를 수정 하십시오 . 감사!


답변

또 다른 옵션은 jq필터 로 사용 하는 것입니다.

jq -sRr @uri

-R( --raw-input)는 입력 라인을 JSON으로 구문 분석하는 대신 문자열로 취급하고 -sR( --slurp --raw-input)는 입력을 단일 문자열로 읽습니다. -r( --raw-output)는 JSON 문자열 리터럴 대신 문자열의 내용을 출력합니다.

입력이 다른 명령의 출력이 아닌 경우 jq문자열 변수 에 저장할 수 있습니다 .

jq -nr --arg v "my shell string" '$v|@uri'

-n( --null-input)는 입력을 읽지 않고 변수 에 문자열로 --arg name value저장 합니다. 쉘에서 확장을 피하기 위해 작은 따옴표로 묶인 필터 에서 변수를 참조합니다 .valuename$namename

Bash 함수로 감싸 인 다음과 같습니다.

function uriencode { jq -nr --arg v "$1" '$v|@uri'; }

또는이 백분율은 모든 바이트를 인코딩합니다.

xxd -p|tr -d \\n|sed 's/../%&/g'


답변

완벽을 기하기 위해 많은 문자를 사용 sed하거나 awk특수 문자 세트 만 변환하므로 코드 크기에 따라 크기가 크며 인코딩해야하는 다른 특수 문자도 변환하지 않습니다.

urlencode의 안전한 방법은 모든 단일 바이트를 인코딩하는 것입니다.

echo -ne 'some random\nbytes' | xxd -plain | tr -d '\n' | sed 's/\(..\)/%\1/g'

여기서 xxd는 입력이 문자가 아닌 바이트로 처리되도록주의하고 있습니다.

편집하다:

xxd는 데비안에서 vim-common 패키지와 함께 제공되며 설치되지 않은 시스템에 설치하고 싶지 않았습니다. 대안은 hexdump데비안의 bsdmainutils 패키지에서 사용 하는 것입니다. 다음 그래프에 따르면 bsdmainutils 및 vim-common은 설치 될 가능성이 거의 동일해야합니다.

http://qa.debian.org/popcon-png.php?packages=vim-common%2Cbsdmainutils&show_installed=1&want_legend=1&want_ticks=1

그럼에도 불구하고 여기서는 hexdump대신에 사용 xxd하고 tr전화 를 피할 수 있는 버전이 있습니다 .

echo -ne 'some random\nbytes' | hexdump -v -e '/1 "%02x"' | sed 's/\(..\)/%\1/g'


답변

변형 중 하나는 추악하지만 단순 할 수 있습니다.

urlencode() {
    local data
    if [[ $# != 1 ]]; then
        echo "Usage: $0 string-to-urlencode"
        return 1
    fi
    data="$(curl -s -o /dev/null -w %{url_effective} --get --data-urlencode "$1" "")"
    if [[ $? != 3 ]]; then
        echo "Unexpected error" 1>&2
        return 2
    fi
    echo "${data##/?}"
    return 0
}

예를 들어 Bruno에서 제안한 것처럼 한 줄짜리 버전이 있습니다 .

date | curl -Gso /dev/null -w %{url_effective} --data-urlencode @- "" | cut -c 3-

# If you experience the trailing %0A, use
date | curl -Gso /dev/null -w %{url_effective} --data-urlencode @- "" | sed -E 's/..(.*).../\1/'


답변

파이썬에서 더 읽기 쉽습니다.

encoded_value=$(python -c "import urllib; print urllib.quote('''$value''')")

트리플 ‘은 값의 작은 따옴표가 아프지 않도록합니다. urllib은 표준 라이브러리에 있습니다. 이 미친 (실제) URL의 예를 들어 작동합니다.

"http://www.rai.it/dl/audio/" "1264165523944Ho servito il re d'Inghilterra - Puntata 7