У меня есть огромный 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: not found
EDIT Почему-то это работает в одной оболочке, но не в другой. Он работает в Git Bash в Windows, но не в Ubuntu 18.04 в Windows. Оба работают под управлением GNU bash 4.4.19, но, очевидно, они немного отличаются друг от друга.
Как @steeldriver указанный, sed
будет метать икру /bin/sh
который является symlinked к /bin/dash
в текущих релизах Ubuntu и не поддерживает функции. Это вызвано тем, что sed
внутренне использование popen
, который всегда мечет икру /bin/sh
(см. человека popen).
Если Вы не можете или не хотеть делать удар оболочкой по умолчанию и потребностью использовать функции удара в sed, можно использовать следующее обходное решение.
Для создания /bin/sh
точка к /bin/bash
, мы сначала используем недолю для порождения нового удара с частным пространством имен монтирования, bindmount /bin/bash
на /bin/dash
и затем выполните команду sed:
unshare -m -r bash -c "mount --bind /bin/bash /bin/dash && sed -e 's/.*/urldecode &/e' big_file.csv"
Тем путем все экспортируемые функции сохраняются. Можно также записать функцию, таким образом, Вы не должны писать целой недоле... часть все время, например:
#!/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
Знайте, тем не менее, что -r
опция unshare
, то, которое необходимо для сможения к bindmount, создает своего рода виртуальную среду, в которой Вы - корень. Полномочия чтения-записи совпадают с пользователем, который звонил unshare
, но uid и ценуроз будут 0. Например, если Вы звоните whoami
внутри urldecode
, это распечатает root
.
Вы могли также просто запустить целый скрипт с помощью недоли:
unshare -m -r bash -c "mount --bind /bin/bash /bin/dash && ./script.sh"
... но ограничения из предыдущего абзаца применяются.