使用 sed 自定义函数失败

使用 sed 自定义函数失败

我有一个巨大的 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。例如,如果您在 内部调用,它将打印。unshareunsharewhoamiurldecoderoot

您也可以使用 unshare 简单地运行整个脚本:

unshare -m -r bash -c "mount --bind /bin/bash /bin/dash && ./script.sh"

...但上一段的限制适用。

相关内容