curlコマンドのデータをurlencodeする方法は?


319

パラメータを受け取り、curlを介してWebサイトに送信するテスト用のbashスクリプトを記述しようとしています。特殊文字が適切に処理されるように、値をURLエンコードする必要があります。これを行う最良の方法は何ですか?

これまでの私の基本的なスクリプトは次のとおりです。

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


回答:


396

を使用しcurl --data-urlencodeます。からman curl

これ--dataは、URLエンコードを実行することを除いて、他のオプションと同様にデータをポストします。CGIに準拠するには、<data>パーツは名前で始まり、その後にセパレータとコンテンツ仕様が続く必要があります。

使用例:

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

詳細については、manページ参照してください。

これには、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

5
http POSTでのみ機能するようです。ドキュメントはこちら:curl.haxx.se/docs/manpage.html#
Stan James

82
@StanJamesこのように使用すると、curlはGETリクエストのエンコーディングも実行できます。 curl -G --data-urlencode "blah=df ssdf sdf" --data-urlencode "blah2=dfsdf sdfsd " http://whatever.com/whatever
kberg 2012年

13
@kberg実際には、これはクエリデータに対してのみ機能します。カールは「?」を追加します urlencoded paramsが続きます。URLの接尾辞(ドキュメントIDのCouchDB GETなど)をurlencodeしたい場合、 '-data-urlencode'は機能しません。
ボケ

1
では機能しませんcurl --data-urlencode "description=![image]($url)" www.example.com。なぜだろう?`
Khurshid Alam

1
@NadavBエスケープ"
ブラックジャック

179

これが純粋な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
}

次の2つの方法で使用できます。

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

4
残念ながら、このスクリプトは 'é'や '½'などの一部の文字で失敗し、それぞれ 'e%FFFFFFFFFFFFFFCC'および '%FFFFFFFFFFFFFFC2'を出力します(文字ごとのループのb / cと思います)。
Matthemattics 2014年

1
私にとってBash 4.3.11(1)では機能しません。JSにフィードできない文字列がJogging «à l'Hèze»生成さJogging%20%abà%20l%27Hèze%bbれますdecodeURIComponent:(
dmcontador

2
その最初のコードブロックで、printfの最後のパラメーターは何を意味しますか?つまり、なぜ二重引用符、単一引用符、ドル記号、文字c、二重引用符なのでしょうか。一重引用符は使えますか?
Colin Fraizer、2016年

1
@dmcontador-謙虚なbashスクリプトであり、マルチバイト文字やユニコードの概念はありません。ń(\u0144)のような文字である場合、単純に%144を出力し、will(\u2561)は%2561として出力されます。これらの正しいrawurlencoded回答は、それぞれ%C5%84%0Aおよび%E2%95%A1です。
Orwellophile 2016年

1
@ColinFraizer単一引用符は、次の文字をその数値に変換するのに役立ちます。ref。pubs.opengroup.org/onlinepubs/9699919799/utilities/...
サム・

94

bashスクリプトの2行目でPerlのURI::Escapeモジュールとuri_escape関数を使用します。

...

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

編集: Chris Johnsenがコメントで提案したように、引用の問題を修正します。ありがとう!


2
URI :: Escapeがインストールされていない可能性があります。その場合は私の答えを確認してください。
blueyed 2009年

これを修正し(echo、パイプ、を使用<>)、$ 2にアポストロフィまたは二重引用符が含まれている場合でも機能するようになりました。ありがとう!
10

9
あなたもをやめechoます:value="$(perl -MURI::Escape -e 'print uri_escape($ARGV[0]);' "$2")"
Chris Johnsen

1
Chris Johnsenのバージョンの方が優れています。テスト式に$ {True}があり、これをエコー経由で使用すると、uri_escape / Perl変数拡張が作動しました。
mm2001

1
@ jrw32982ええ、振り返ってみると、このタスクを実行するために別の言語を使用するのは良いことです。私はできれば、私は私のdownvoteを取り戻すが、それが現在ではロックされて悲しい思います。
thecoshman

69

別のオプションは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'

3
<3 it ...最高で受け入れられたIMOである必要があります(そうすればcurl、そのエンコードを機能させることができ、bashに許容できるビルトインがある場合-しかし、jq快適なレベルを達成するには程遠いですこのツール)
2017年

5
私と同じことを不思議に思う人にとって@uriは、変数ではなく、文字列のフォーマットとエスケープに使用されるリテラルjqフィルターです。詳細については、jqのマニュアルを参照してください(申し訳ありませんが、直接リンクはなく@uri、ページで検索する必要があります...)
ssc

xxdバージョンは、まさに私が探していたものです。少し汚れていても、短くて依存関係はありません
Rian Sanderson '21

1
url-encodeへのjqの使用例:printf "http://localhost:8082/" | jq -sRr '@uri'
Ashutosh Jindal

67

完全を期すために、特殊な文字セットを使用sedまたはawk変換するだけの多くのソリューションはコードサイズが非常に大きく、エンコードする必要がある他の特殊文字も変換しないようにしています。

urlencodeの安全な方法は、すべてのバイトをエンコードすることです-許可されていたバイトも。

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

ここでxxdは、入力が文字ではなくバイトとして処理されるように注意しています。

編集:

xxdには、Debianのvim-commonパッケージが付属しており、私はそれがインストールされていないシステムで、インストールしたくありませんでした。代わりに使用することですhexdump、Debianの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'

1
xxd -plain後に発生するはずtr -d '\n'です!
qdii

3
@qdiiなんで?これは、改行をurlencodeすることを不可能にするだけでなく、xxdによって作成された改行を出力に誤って挿入します。
josch

1
@josch。これはまったく間違っています。最初に、すべての\n文字がに翻訳さxxd -plain0aます。それは私の言葉を服用しないでください、それを自分で試してみてください。echo -n -e '\n' | xxd -plainこれはあなたのことを証明しているtr -d '\n'任意の存在することはできません、ここで役に立たない\nの後xxd -plain 、第二にecho foobar、独自の追加\n文字列の末尾に文字を、そうxxd -plainで送られていないfoobarが、との予想通りfoobar\n。次に、xxd -plain それをで終わるいくつかの文字列に変換する0aため、ユーザーには不適切です。あなたはそれを解決するために追加-nすることができechoます。
qdii

6
@qdiiは確かにエコー用の-nがありませんでしたが、xxd呼び出しは呼び出しの前に属していtr -dます。それはそこに属しているため、の改行foobarはによって翻訳されxxdます。呼び出しのtr -d後はxxd、xxdが生成する改行を削除することです。xxd改行を生成するのに十分な長さのfoobarはないようですが、長い入力の場合は生成されます。だからtr -d必要です。あなたの仮定とtr -dは対照的に、それは入力からではなくxxd出力から改行を削除することでした。入力の改行を保持したい。あなたの唯一の有効なポイントは、そのエコーが不必要な改行を追加することです。
josch 2012

1
@qdiiで違反はありません- echo -n私が本当に欠落していたものを除いて、私はあなたが間違っていると思います
josch

62

亜種の1つは、醜いかもしれませんが、単純です:

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/'

1
これはcURLのURLエンコーディングを再利用する非常に賢い方法だと思います。
solidsnack 2012年

13
これは絶対に素晴らしいです!簡単にわかるように、1行にしておけば幸いです。dateコマンドの結果をURLエンコードするには... date | curl -Gso /dev/null -w %{url_effective} --data-urlencode @- "" | cut -c 3-cutcurlの出力は
厳密に

2
@BrunoBronoskyワンライナーバリアントは優れていますが、エンコーディングの最後に「%0A」が追加されているようです。ユーザーは注意してください。機能バージョンにはこの問題はないようです。
levigroker

7
%0A最後に回避するには、のprintf代わりにを使用しますecho
kenorb 2018年

2
ワンライナーは素晴らしい
スティーブンブルーム

49

私はそれがpythonでより読みやすいと思います:

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

2
引用符と三重引用符を使用した特殊文字に問題がありましたが、これは基本的にすべてに対して機能するように思われました。 write(urllib.quote(sys.stdin.read())) ")";
中傷モニカチェリオを停止します。

Python 3バージョンはになりますencoded_value=$(python3 -c "import urllib.parse; print (urllib.parse.quote('''$value'''))")
クレシャル

1
python -c 'import urllib, sys; sys.stdout.writelines(urllib.quote_plus(l, safe="/\n") for l in sys.stdin)'ほとんどの問題を引用していない、とすべきメモリ/スピード、効率的な(細めのために保存し、チェックしていない)こと
アロイスMahdal

2
後でコードとして解析される文字列にsys.argv置き換えるよりも、参照する方がはるかに安全$valueです。value含まれている場合は''' + __import__("os").system("rm -rf ~") + '''どうなりますか?
Charles Duffy、

2
python -c "import urllib;print urllib.quote(raw_input())" <<< "$data"
Rockallite 2017

30

次のスニペットは、プログラム呼び出しのチェーンに貼り付けるのに役立ちます。URI:: Escapeがインストールされていない可能性があります。

perl -p -e 's/([^A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg'

ソース


4
私のために働いた。私はそれをperl -lpe ...(文字ell)に変更しました。これにより、目的に必要な末尾の改行が削除されました。
JohnnyLambada

2
参考までに、これの逆を行うには、perl -pe 's/\%(\w\w)/chr hex $1/ge'(ソース:unix.stackexchange.com/questions/159253/…)を使用します
Sridhar Sarnobat '10

2
エンコードする必要のある文字に応じて、これを簡略化しperl -pe 's/(\W)/sprintf("%%%02X", ord($1))/ge'て文字、数字、アンダースコアを許可し、それ以外はすべてエンコードすることができます。
robru 2016年

23

GETリクエストを実行して純粋なカールを使用したい場合は、追加してください--get、@ Jacobのソリューションにしてください。

次に例を示します。

curl -v --get --data-urlencode "access_token=$(cat .fb_access_token)" https://graph.facebook.com/me/feed

15

awkバージョンへの直接リンク:http : //www.shelldorado.com/scripts/cmds/urlencode
私は何年も使用しており、魅力のように機能します

:
##########################################################################
# Title      :  urlencode - encode URL data
# Author     :  Heiner Steven (heiner.steven@odn.de)
# Date       :  2000-03-15
# Requires   :  awk
# Categories :  File Conversion, WWW, CGI
# SCCS-Id.   :  @(#) urlencode  1.4 06/10/29
##########################################################################
# Description
#   Encode data according to
#       RFC 1738: "Uniform Resource Locators (URL)" and
#       RFC 1866: "Hypertext Markup Language - 2.0" (HTML)
#
#   This encoding is used i.e. for the MIME type
#   "application/x-www-form-urlencoded"
#
# Notes
#    o  The default behaviour is not to encode the line endings. This
#   may not be what was intended, because the result will be
#   multiple lines of output (which cannot be used in an URL or a
#   HTTP "POST" request). If the desired output should be one
#   line, use the "-l" option.
#
#    o  The "-l" option assumes, that the end-of-line is denoted by
#   the character LF (ASCII 10). This is not true for Windows or
#   Mac systems, where the end of a line is denoted by the two
#   characters CR LF (ASCII 13 10).
#   We use this for symmetry; data processed in the following way:
#       cat | urlencode -l | urldecode -l
#   should (and will) result in the original data
#
#    o  Large lines (or binary files) will break many AWK
#       implementations. If you get the message
#       awk: record `...' too long
#        record number xxx
#   consider using GNU AWK (gawk).
#
#    o  urlencode will always terminate it's output with an EOL
#       character
#
# Thanks to Stefan Brozinski for pointing out a bug related to non-standard
# locales.
#
# See also
#   urldecode
##########################################################################

PN=`basename "$0"`          # Program name
VER='1.4'

: ${AWK=awk}

Usage () {
    echo >&2 "$PN - encode URL data, $VER
usage: $PN [-l] [file ...]
    -l:  encode line endings (result will be one line of output)

The default is to encode each input line on its own."
    exit 1
}

Msg () {
    for MsgLine
    do echo "$PN: $MsgLine" >&2
    done
}

Fatal () { Msg "$@"; exit 1; }

set -- `getopt hl "$@" 2>/dev/null` || Usage
[ $# -lt 1 ] && Usage           # "getopt" detected an error

EncodeEOL=no
while [ $# -gt 0 ]
do
    case "$1" in
        -l) EncodeEOL=yes;;
    --) shift; break;;
    -h) Usage;;
    -*) Usage;;
    *)  break;;         # First file name
    esac
    shift
done

LANG=C  export LANG
$AWK '
    BEGIN {
    # We assume an awk implementation that is just plain dumb.
    # We will convert an character to its ASCII value with the
    # table ord[], and produce two-digit hexadecimal output
    # without the printf("%02X") feature.

    EOL = "%0A"     # "end of line" string (encoded)
    split ("1 2 3 4 5 6 7 8 9 A B C D E F", hextab, " ")
    hextab [0] = 0
    for ( i=1; i<=255; ++i ) ord [ sprintf ("%c", i) "" ] = i + 0
    if ("'"$EncodeEOL"'" == "yes") EncodeEOL = 1; else EncodeEOL = 0
    }
    {
    encoded = ""
    for ( i=1; i<=length ($0); ++i ) {
        c = substr ($0, i, 1)
        if ( c ~ /[a-zA-Z0-9.-]/ ) {
        encoded = encoded c     # safe character
        } else if ( c == " " ) {
        encoded = encoded "+"   # special handling
        } else {
        # unsafe character, encode it as a two-digit hex-number
        lo = ord [c] % 16
        hi = int (ord [c] / 16);
        encoded = encoded "%" hextab [hi] hextab [lo]
        }
    }
    if ( EncodeEOL ) {
        printf ("%s", encoded EOL)
    } else {
        print encoded
    }
    }
    END {
        #if ( EncodeEOL ) print ""
    }
' "$@"

ASCIIの代わりにUTF-8エンコーディングを取得する簡単なバリエーションはありますか?
avgvstvs 2015年

15

これが一番良いかもしれません:

after=$(echo -e "$before" | od -An -tx1 | tr ' ' % | xargs printf "%s")

これは私にとって2つの追加で機能します。1。-eを-nで置き換えて、引数の最後に改行が追加されないようにします。2。 '%%'をprintf文字列に追加して、各ペアの前に%を付けます。 16進数。
Rob Fagen、2016年

先行$ブラケットを追加した後に機能します after=$(echo -e ...
Roman Rhrn Nesterov

1
これがどのように機能するか説明してください。odコマンドは一般的ではありません。
Mark Stosberg、

これはod、GNUとは異なる出力形式を使用するため、OS Xでは機能しませんod。例えば、printf aa|od -An -tx1 -v|tr \ -印刷さ-----------61--61--------------------------------------------------------OS Xのとodし、-61-61GNUにodod -An -tx1 -v|sed 's/ */ /g;s/ *$//'|tr \ %|tr -d \\nOS XとodGNU のどちらでも使用できますod。POSIXではなくxxd -p|sed 's/../%&/g'|tr -d \\nても同じことを行います。xxdod
nisetama

2
これはうまくいくかもしれませんが、すべての文字をエスケープします
Charlie

11

外部プログラムを呼び出さないBashソリューションを次に示します。

uriencode() {
  s="${1//'%'/%25}"
  s="${s//' '/%20}"
  s="${s//'"'/%22}"
  s="${s//'#'/%23}"
  s="${s//'$'/%24}"
  s="${s//'&'/%26}"
  s="${s//'+'/%2B}"
  s="${s//','/%2C}"
  s="${s//'/'/%2F}"
  s="${s//':'/%3A}"
  s="${s//';'/%3B}"
  s="${s//'='/%3D}"
  s="${s//'?'/%3F}"
  s="${s//'@'/%40}"
  s="${s//'['/%5B}"
  s="${s//']'/%5D}"
  printf %s "$s"
}

4
これは、bashのバージョン間で動作が異なります。RHEL 6.9では、bashは4.1.2であり、単一引用符が含まれています。Debian 9とbash 4.4.12は一重引用符で問題ありませんが。一重引用符を削除すると、両方で機能します。s = "$ {s // '、' /%2C}"
muni764

1
私はあなたの発見を反映するために回答を更新しました、@ muni764。
davidchambers

ただ警告...これは文字のようなものをエンコードしませんá
diogovk

10
url=$(echo "$1" | sed -e 's/%/%25/g' -e 's/ /%20/g' -e 's/!/%21/g' -e 's/"/%22/g' -e 's/#/%23/g' -e 's/\$/%24/g' -e 's/\&/%26/g' -e 's/'\''/%27/g' -e 's/(/%28/g' -e 's/)/%29/g' -e 's/\*/%2a/g' -e 's/+/%2b/g' -e 's/,/%2c/g' -e 's/-/%2d/g' -e 's/\./%2e/g' -e 's/\//%2f/g' -e 's/:/%3a/g' -e 's/;/%3b/g' -e 's//%3e/g' -e 's/?/%3f/g' -e 's/@/%40/g' -e 's/\[/%5b/g' -e 's/\\/%5c/g' -e 's/\]/%5d/g' -e 's/\^/%5e/g' -e 's/_/%5f/g' -e 's/`/%60/g' -e 's/{/%7b/g' -e 's/|/%7c/g' -e 's/}/%7d/g' -e 's/~/%7e/g')

これにより、$ 1内の文字列がエンコードされ、$ urlに出力されます。ただし、必要に応じてvarに入れる必要はありません。ところで、sed for tabはスペースに変換されると考えられていなかった


5
これは推奨される方法ではないと感じています。
コーディグレイ

2
あなたの気持ちを説明してください...私が述べたことは機能し、いくつかのスクリプトで使用したので、リストしたすべての文字で機能することがわかります。このタイトルが「bashスクリプトからのURLEncode」であるので、誰かが私のコードを使用せずにperlを使用しない理由を説明してください。perlスクリプトではありません。
manoflinux

時には真珠溶液が必要ないので、これは便利です
Yuval Rimar

3
これはブラックリストが悪い習慣であり、とにかくこれはユニコードに不親切なので、これを行うには推奨される方法ではありません。
Ekevoo 2011

これは、cat file.txtと互換性のある最もフレンドリーなソリューションでした
mrwaim '20年


7

perlを必要としないソリューションを探している方のために、hexdumpとawkのみが必要なソリューションを以下に示します。

url_encode() {
 [ $# -lt 1 ] && { return; }

 encodedurl="$1";

 # make sure hexdump exists, if not, just give back the url
 [ ! -x "/usr/bin/hexdump" ] && { return; }

 encodedurl=`
   echo $encodedurl | hexdump -v -e '1/1 "%02x\t"' -e '1/1 "%_c\n"' |
   LANG=C awk '
     $1 == "20"                    { printf("%s",   "+"); next } # space becomes plus
     $1 ~  /0[adAD]/               {                      next } # strip newlines
     $2 ~  /^[a-zA-Z0-9.*()\/-]$/  { printf("%s",   $2);  next } # pass through what we can
                                   { printf("%%%s", $1)        } # take hex value of everything else
   '`
}

ネット上のいくつかの場所からのステッチとローカルでの試行錯誤。それはうまくいきます!


7

uni2asciiは非常に便利です。

$ echo -ne '你好世界' | uni2ascii -aJ
%E4%BD%A0%E5%A5%BD%E4%B8%96%E7%95%8C

2
これは、ASCII範囲の文字%(引用-s
符など

7

Perlに依存したくない場合は、sedを使用することもできます。各キャラクターは個別にエスケープする必要があるため、少し面倒です。以下の内容のファイルを作成して呼び出しますurlencode.sed

s/%/%25/g
s/ /%20/g
s/ /%09/g
s/!/%21/g
s/"/%22/g
s/#/%23/g
s/\$/%24/g
s/\&/%26/g
s/'\''/%27/g
s/(/%28/g
s/)/%29/g
s/\*/%2a/g
s/+/%2b/g
s/,/%2c/g
s/-/%2d/g
s/\./%2e/g
s/\//%2f/g
s/:/%3a/g
s/;/%3b/g
s//%3e/g
s/?/%3f/g
s/@/%40/g
s/\[/%5b/g
s/\\/%5c/g
s/\]/%5d/g
s/\^/%5e/g
s/_/%5f/g
s/`/%60/g
s/{/%7b/g
s/|/%7c/g
s/}/%7d/g
s/~/%7e/g
s/      /%09/g

それを使用するには、次の操作を行います。

STR1=$(echo "https://www.example.com/change&$ ^this to?%checkthe@-functionality" | cut -d\? -f1)
STR2=$(echo "https://www.example.com/change&$ ^this to?%checkthe@-functionality" | cut -d\? -f2)
OUT2=$(echo "$STR2" | sed -f urlencode.sed)
echo "$STR1?$OUT2"

これは、文字列をエンコードが必要な部分と細かい部分に分割し、それを必要とする部分をエンコードしてから、つなぎ合わせます。

あなたはそれをshスクリプトに入れて便利にすることができます、おそらくそれはエンコードするパラメータを取ってあなたのパスに置いて、それから単に呼び出すことができます:

urlencode https://www.exxample.com?isThisFun=HellNo

ソース


7

encodeURIComponentPerlでJavaScriptをエミュレートできます。コマンドは次のとおりです。

perl -pe 's/([^a-zA-Z0-9_.!~*()'\''-])/sprintf("%%%02X", ord($1))/ge'

これをbashエイリアスとして設定できます.bash_profile

alias encodeURIComponent='perl -pe '\''s/([^a-zA-Z0-9_.!~*()'\''\'\'''\''-])/sprintf("%%%02X",ord($1))/ge'\'

これで次のようにパイプできますencodeURIComponent

$ echo -n 'hèllo wôrld!' | encodeURIComponent
h%C3%A8llo%20w%C3%B4rld!

6

ノードのバージョンは次のとおりです。

uriencode() {
  node -p "encodeURIComponent('${1//\'/\\\'}')"
}

1
単一のバックスラッシュや改行のように、単一引用符の間に無効な文字列が他にある場合、これは壊れませんか?
スチュアートP.ベントレー

いい視点ね。Bashのすべての問題のある文字をエスケープするという問題に行く場合は、直接置換を実行してnode完全に回避することもできます。Bashのみのソリューションを投稿しました。:)
davidchambers 2017年

1
ページ上の他の場所で見つかったこの変形はSTDINから値を読み出すことにより、引用問題を回避:node -p 'encodeURIComponent(require("fs").readFileSync(0))'
マーク・Stosberg

6

問題は、これをbashで行うことです。実際には、「urlencode」という正確に実行する単一のコマンドがあるため、pythonやperlは必要ありません。

value=$(urlencode "${2}")

たとえば、上記のperlの回答ではすべての文字が正しくエンコードされないため、これもはるかに優れています。Wordから取得した長いダッシュで試してみると、間違ったエンコーディングが取得されます。

このコマンドを提供するには、「gridsite-clients」がインストールされている必要があります。


1
私のバージョンのbash(GNU 3.2)にはがありませんurlencode。どのバージョンを使用していますか?
Sridhar Sarnobat

1
4.3.42を使用していますが、urlencodeコマンドは「gridsite-clients」によって提供されます。それをインストールしてみてください、あなたは大丈夫です。
ディラン

5
したがって、あなたの答えは、他のものをインストールする必要があるもの(python、perl、luaなど)より優れていません
Cyrille Pontvieux

言語(およびライブラリ)全体ではなく、単一のユーティリティをインストールするだけでよいことを除いて、加えて、それが何をしているかを確認するのは非常に簡単で明確です。
ディラン

このコマンドを提供するパッケージ/プロジェクトページへの最初のリンクは役に立ちました。
Doron Behar

6

単純なPHPオプション:

echo 'part-that-needs-encoding' | php -R 'echo urlencode($argn);'

4

Ruby、完全を期す

value="$(ruby -r cgi -e 'puts CGI.escape(ARGV[0])' "$2")"

4

別のphpアプローチ:

echo "encode me" | php -r "echo urlencode(file_get_contents('php://stdin'));"

2
echo改行文字(16進数0xa)を追加します。それを停止するには、を使用しますecho -n
Mathew Hall

3

これが、組み込みシステム用のbusybox ashシェルの私のバージョンです。元々、Orwellophileのバリアントを採用しました。

urlencode()
{
    local S="${1}"
    local encoded=""
    local ch
    local o
    for i in $(seq 0 $((${#S} - 1)) )
    do
        ch=${S:$i:1}
        case "${ch}" in
            [-_.~a-zA-Z0-9]) 
                o="${ch}"
                ;;
            *) 
                o=$(printf '%%%02x' "'$ch")                
                ;;
        esac
        encoded="${encoded}${o}"
    done
    echo ${encoded}
}

urldecode() 
{
    # urldecode <string>
    local url_encoded="${1//+/ }"
    printf '%b' "${url_encoded//%/\\x}"
}

2

これを行うPOSIX関数は次のとおりです。

encodeURIComponent() {
  awk 'BEGIN {while (y++ < 125) z[sprintf("%c", y)] = y
  while (y = substr(ARGV[1], ++j, 1))
  q = y ~ /[[:alnum:]_.!~*\47()-]/ ? q y : q sprintf("%%%02X", z[y])
  print q}' "$1"
}

例:

value=$(encodeURIComponent "$2")

ソース


2

これはLuaを使用した1行の変換です。blueyedの回答に似ていますが、RFC 3986のすべての予約されていない文字がエンコードされていない(この回答のように)点が異なります

url=$(echo 'print((arg[1]:gsub("([^%w%-%.%_%~])",function(c)return("%%%02X"):format(c:byte())end)))' | lua - "$1")

さらに、文字列の改行がLFからCRLFに変換されていることを確認する必要がある場合があります。その場合gsub("\r?\n", "\r\n")、パーセントエンコードの前にチェーンにを挿入できます。

application / x-www-form-urlencodedの非標準のスタイルで改行を正規化し、スペースを '%20'の代わりに '+'としてエンコードするバリアントがあります(これはおそらく同様の手法を使用したPerlスニペット)。

url=$(echo 'print((arg[1]:gsub("\r?\n", "\r\n"):gsub("([^%w%-%.%_%~ ]))",function(c)return("%%%02X"):format(c:byte())end):gsub(" ","+"))' | lua - "$1")

1

PHPがインストールされていると、次のように使用します。

URL_ENCODED_DATA=`php -r "echo urlencode('$DATA');"`

1

これは、rawurlencode関数とrawurldecode関数を含む、orwellophileの回答のkshバージョンです(リンク:curlコマンドのデータをurlencodeする方法?)。コメントを投稿するのに十分な担当者がいないため、新しい投稿です。

#!/bin/ksh93

function rawurlencode
{
    typeset string="${1}"
    typeset strlen=${#string}
    typeset encoded=""

    for (( pos=0 ; pos<strlen ; pos++ )); do
        c=${string:$pos:1}
        case "$c" in
            [-_.~a-zA-Z0-9] ) o="${c}" ;;
            * )               o=$(printf '%%%02x' "'$c")
        esac
        encoded+="${o}"
    done
    print "${encoded}"
}

function rawurldecode
{
    printf $(printf '%b' "${1//%/\\x}")
}

print $(rawurlencode "C++")     # --> C%2b%2b
print $(rawurldecode "C%2b%2b") # --> C++

1

javascriptよりもURLの解析に優れているものは何ですか?

node -p "encodeURIComponent('$url')"

op質問の範囲外です。バッシュではなく、カールではありません。ノードが利用可能であれば、私は確かに非常にうまく機能します。
Cyrille Pontvieux 2017

python / perlの回答ではなく、なぜこれに反対票を投じるのですか?さらに、これが元の質問「curlコマンドのデータをurlencodeする方法」に応答しないのはなぜですか。これはbashスクリプトから使用でき、結果をcurlコマンドに渡すことができます。
Nestor Urquiza 2017

私も他の人に反対票を投じました。問題は、bashスクリプトでこれを行う方法でした。node / js、python、perlなどの別の言語を使用する場合は、curlを直接使用する必要はありません。
Cyrille Pontvieux 2017

2
私は気にせずに反対投票しましたが、このコマンドの問題は、JavaScriptで使用するためにデータを適切にエスケープする必要があることです。一重引用符とバックスラッシュの狂気で試してみてください。ノードを使用したい場合は、stdinのようなものをよく読んでくださいnode -p 'encodeURIComponent(require("fs").readFileSync(0))'
Michael Krelin-ハッカー

1
@ MichaelKrelin-hackerのソリューションに注意してください。STDINからデータをパイピングする場合は、末尾の改行を含めないようにしてください。たとえば、echo | ...不正ですがecho -n | ...、改行を抑制します。
Mark Stosberg、

0

以下はOrwellophileの回答に基づいていますが、LC_ALL = C(vte.shからのトリック)を設定することにより、コメントで言及されているマルチバイトのバグを解決します。関数の適切なPROMPT_COMMANDの形式で記述しました。それが私がそれを使用する方法だからです。

print_path_url() {
  local LC_ALL=C
  local string="$PWD"
  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
  printf "\033]7;file://%s%s\007" "${HOSTNAME:-}" "${encoded}"
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.