我有一个巨大的 csv 文件,它是经过 url 编码的。
我想解码所有的台词,我想sed可以帮我解决这个问题,但我无法让它发挥作用。
这是我的脚本:
#!/bin/bash
function urldecode() {
# urldecode <string>
# from https://gist.github.com/cdown/1163649
local url_encoded="${1//+/ }"
printf '%b' "${url_encoded//%/\\x}"
}
export -f urldecode
sed -e 's/.*/urldecode &/e' big_file.csv
这会产生重复的错误信息sh: 1: urldecode: 未找到
编辑:不知何故,这似乎在一个 shell 中有效,但在另一个 shell 中无效。它在 Windows 上的 Git Bash 中有效 - 但在 Windows 上的 Ubuntu 18.04 中无效。两者都运行 GNU bash 4.4.19,但显然版本略有不同。
答案1
正如 @steeldriver 指出的那样,sed
将生成当前 Ubuntu 版本中/bin/sh
符号链接到的/bin/dash
,并且不支持函数。这是因为sed
内部使用popen
,它总是产卵/bin/sh
(见曼波彭)。
如果你不能或不想将 bash 设为默认 shell并且需要在 sed 中使用 bash 函数,您可以使用以下解决方法。
为了说明/bin/sh
,/bin/bash
我们首先使用取消共享要生成具有私有挂载命名空间的新 bash,请绑定挂载/bin/bash
,/bin/dash
然后执行 sed 命令:
unshare -m -r bash -c "mount --bind /bin/bash /bin/dash && sed -e 's/.*/urldecode &/e' big_file.csv"
这样,所有导出的函数都会被保留。您还可以编写一个函数,这样就不必一直编写整个 unshare... 部分,例如:
#!/bin/bash
function mysed() {
sedcommand=sed
# restore quotes around each script
while test $# -gt 0; do
[[ "$1" == "-e" ]] && { shift; sedcommand="$sedcommand -e '$1'"; } || sedcommand="$sedcommand $1"; shift
done
unshare -m -r bash -c "mount --bind /bin/bash /bin/dash && $sedcommand"
}
function urldecode() {
local url_encoded="${1//+/ }"
printf '%b' "${url_encoded//%/\\x}"
}
export -f urldecode
mysed -e 's|.*|urldecode &|e' big_file.csv
但请注意,bindmount 所需的-r
选项会创建一种虚拟环境,您在其中是 root 用户。读/写权限与调用 的用户相同,但 uid 和 gid 将为 0。例如,如果您在 内部调用,它将打印。unshare
unshare
whoami
urldecode
root
您也可以使用 unshare 简单地运行整个脚本:
unshare -m -r bash -c "mount --bind /bin/bash /bin/dash && ./script.sh"
...但上一段的限制适用。