我试图写一个bash脚本测试,需要一个参数,并通过curl发送到网站。我需要url编码的值,以确保特殊字符被正确处理。最好的方法是什么?

这是我到目前为止的基本脚本:

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

当前回答

下面是一个POSIX函数:

url_encode() {
   awk 'BEGIN {
      for (n = 0; n < 125; n++) {
         m[sprintf("%c", n)] = n
      }
      n = 1
      while (1) {
         s = substr(ARGV[1], n, 1)
         if (s == "") {
            break
         }
         t = s ~ /[[:alnum:]_.!~*\47()-]/ ? t s : t sprintf("%%%02X", m[s])
         n++
      }
      print t
   }' "$1"
}

例子:

value=$(url_encode "$2")

其他回答

另一个选择是使用jq:

$ printf %s 'input text'|jq -sRr @uri
input%20text
$ jq -rn --arg x 'input text' '$x|@uri'
input%20text

-r(——raw-output)输出字符串的原始内容,而不是JSON字符串字面量。-n(——null-input)不从STDIN读取输入。

-R(——raw-input)将输入行视为字符串,而不是将其解析为JSON,而-sR(——slurp——raw-input)将输入读入单个字符串。如果你的输入只包含一行,或者你不想用%0A替换换行符,你可以用-Rr替换-sRr:

$ printf %s\\n multiple\ lines of\ text|jq -Rr @uri
multiple%20lines
of%20text
$ printf %s\\n multiple\ lines of\ text|jq -sRr @uri
multiple%20lines%0Aof%20text%0A

或者这个百分比编码所有字节:

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

以下是基于奥威尔的回答,但解决了多字节 通过设置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}"
}

问题是关于在bash中这样做,不需要python或perl,因为实际上有一个命令,它完全是你想要的-“urlencode”。

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

这也更好,因为上面的perl答案,例如,没有正确编码所有字符。尝试使用从Word中获得的长破折号,你会得到错误的编码。

注意,你需要安装"gridsite-clients"来提供这个命令:

sudo apt install gridsite-clients

我发现下面的代码片段很有用,可以将它插入到一个程序调用链中,其中URI::Escape可能没有安装:

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

(源)

Python 3基于@sandro在2010年的好答案:

echo "Test & /me" | python -c "import urllib.parse;print (urllib.parse.quote(input()))"

测试% 20% 26% 20 /我