Как присвоить данные для команды curl?

Я пытаюсь написать сценарий bash для тестирования, который принимает параметр и отправляет его через curl на веб-сайт. Мне нужно, чтобы url закодировал значение, чтобы убедиться, что специальные символы обработаны должным образом. Каков наилучший способ сделать это?

Вот мой основной сценарий:

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

Использовать curl --data-urlencode ; от man curl :

Эти данные данных, аналогичные другим параметрам --data , за исключением того, что это выполняет URL-кодирование. Чтобы быть совместимым с CGI, часть должна начинаться с имени, за которым следует разделитель и спецификация содержимого.

Пример использования:

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

См. Справочную страницу для получения дополнительной информации.

Для этого требуется curl 7.18.0 или новее (выпущен в январе 2008 г.) . Используйте curl -V чтобы проверить, какая у вас версия.

Вот чистый ответ BASH.

 rawurlencode() { local string="${1}" local strlen=${#string} local encoded="" local pos co for (( pos=0 ; pos 

Вы можете использовать его двумя способами:

 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 

Используйте Perl URI::Escape module и функцию uri_escape во второй строке вашего скрипта bash:

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

Изменить: исправить проблемы с цитированием, как это было предложено Крисом Джонсеном в комментариях. Благодаря!

для полноты, многие решения, использующие sed или awk переводят только специальный набор символов и, следовательно, довольно велики по размеру кода, а также не переводят другие специальные символы, которые должны быть закодированы.

безопасным способом urlencode было бы просто кодировать каждый байт – даже те, которые были бы разрешены.

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

Здесь xxd заботится о том, чтобы вход обрабатывался как байты, а не символы.

редактировать:

xxd поставляется с vim-common пакетом в Debian, и я был только в системе, где он не был установлен, и я не хотел его устанавливать. Алтернативным является использование hexdump из пакета bsdmainutils в Debian. Согласно следующему графику, 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' 

Я нахожу его более читаемым в 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 

Один из вариантов, может быть уродливым, но простым:

 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 } 

Вот пример с одним слоем (как предложил Бруно ):

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

Я нашел следующий fragment полезный, чтобы вставить его в цепочку вызовов программ, где URI :: Escape может не быть установлен:

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

( источник )

Если вы хотите запустить GET запрос и использовать чистый curl, просто добавьте --get решение @ Jacob.

Вот пример:

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

Другой вариант – использовать jq :

 jq -s -R -r @uri 

-s ( --slurp ) считывает входные строки в массив и -s -R ( --slurp --raw-input ) считывает ввод в одну строку. -r ( --raw-output ) выводит содержимое строк вместо строковых литералов JSON.

Или этот процент кодирует все байты:

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

Прямая ссылка на awk-версию: http://www.shelldorado.com/scripts/cmds/urlencode
Я использовал его в течение многих лет, и он работает как шарм

 : ########################################################################## # Title : urlencode - encode URL data # Author : Heiner Steven ([email protected]) # 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 ie 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 "[email protected]"; exit 1; } set -- `getopt hl "[email protected]" 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 ABCDEF", 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 "" } ' "[email protected]" 

Это может быть лучшим:

 after=$(echo -e "$before" | od -An -tx1 | tr ' ' % | xargs printf "%s") 
 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, если хотите. BTW не включал sed для вкладки, думал, что он превратит его в пробелы

Для тех из вас, кто ищет решение, которое не нуждается в 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 '` } 

Сшитые из нескольких мест по сети и некоторые местные проб и ошибок. Он отлично работает!

Использование php из сценария оболочки:

 value="http://www.google.com" encoded=$(php -r "echo rawurlencode('$value');") # encoded = "http%3A%2F%2Fwww.google.com" echo $(php -r "echo rawurldecode('$encoded');") # returns: "http://www.google.com" 
  1. http://www.php.net/manual/en/function.rawurlencode.php
  2. http://www.php.net/manual/en/function.rawurldecode.php

uni2ascii очень удобен:

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

Если вы не хотите зависеть от 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?%[email protected]" | cut -d\? -f1) STR2=$(echo "https://www.example.com/change&$ ^this to?%[email protected]" | cut -d\? -f2) OUT2=$(echo "$STR2" | sed -f urlencode.sed) echo "$STR1?$OUT2" 

Это разделит строку на часть, которая требует кодирования, а часть, которая в порядке, закодирует нужную ей часть, затем сшивается вместе.

Вы можете поместить это в sh-скрипт для удобства, возможно, для этого требуется параметр для кодирования, поместить его на свой путь, а затем вы можете просто позвонить:

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

источник

Вопрос заключается в том, чтобы сделать это в bash, и нет необходимости в python или perl, поскольку на самом деле существует единственная команда, которая делает именно то, что вы хотите – «urlencode».

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

Это также намного лучше, так как вышеупомянутый ответ perl, например, не кодирует все символы правильно. Попробуйте это с длинной чертой, которую вы получаете от Word, и получите неправильную кодировку.

Обратите внимание: для обеспечения этой команды вам требуются «gridsite-clients».

Вы можете эмулировать encodeURIComponent javascript в perl. Вот команда:

 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! 

Простая опция PHP:

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

Другой подход php:

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

Вот версия узла:

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

Ruby, для полноты

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

Вот решение 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" } 

Вот функция POSIX для этого:

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

Пример:

 value=$(encodeURIComponent "$2") 

Источник

Вот однострочное преобразование с использованием Lua, похожее на ответ 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") 

После установки php я использую этот способ:

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

Это ksh-версия ответа orwellophile, содержащая функции rawurlencode и rawurldecode (ссылка: как присвоить данные для команды curl? ). У меня недостаточно отзывов, чтобы опубликовать комментарий, следовательно, новый пост.

 #!/bin/ksh93 function rawurlencode { typeset string="${1}" typeset strlen=${#string} typeset encoded="" for (( pos=0 ; pos C%2b%2b print $(rawurldecode "C%2b%2b") # --> C++ 

Вот моя версия для загрузочной ящички busybox для встроенной системы, я изначально принял вариант Оверволофила:

 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  local url_encoded="${1//+/ }" printf '%b' "${url_encoded//%/\\x}" } 

Ниже приводится ответ Овервелофила, но решается многобайтовая ошибка, упомянутая в комментариях, устанавливая LC_ALL = C (трюк от vte.sh). Я написал его в виде функции, соответствующей PROMPT_COMMAND, потому что именно так я ее использую.

 print_path_url() { local LC_ALL=C local string="$PWD" local strlen=${#string} local encoded="" local pos co for (( pos=0 ; pos 

Что будет анализировать URL-адреса лучше, чем javascript?

 node -p "encodeURIComponent('$url')" 
  • Разделить строку с точкой в ​​качестве разделителя
  • Размер файла формата как MB, GB и т. Д.
  • Получить n-й символ строки в языке программирования Swift
  • Строка неизменна. В чем же смысл?
  • Репликация массива по элементам в Matlab
  • C / C ++: оптимизация указателей на строковые константы
  • В чем преимущество непрерывности String?
  • Как превратить String в InputStreamReader в java?
  • Строка C ++ для enums
  • искать текстовый файл с помощью c # и отображать номер строки и полную строку, содержащую ключевое слово поиска
  • Как форматировать строки в Java
  • Давайте будем гением компьютера.