테스트를 위해 매개 변수를 사용하고 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
:
이것은
--data
URL 인코딩을 수행한다는 점을 제외 하고 다른 옵션과 마찬가지로 데이터를 게시합니다 . 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
저장 합니다. 쉘에서 확장을 피하기 위해 작은 따옴표로 묶인 필터 에서 변수를 참조합니다 .value
name
$name
name
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은 설치 될 가능성이 거의 동일해야합니다.
그럼에도 불구하고 여기서는 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