LINUX.ORG.RU

Портабельный string substitution на sh

 , ,


0

4

Существует ли более простой портабельный (POSIX-совместимый) способ заменить в строке подстроку, чем этот?

plain_subst() {
	local s="$1"
	local p_r='s/[.*[^$]/\\&/g'
	local p="`printf "%s\n" "$2" | sed "$p_r"`"
	local r_r='s/[&\\\/]/\\&/g'
	local r="`printf "%s\n" "$3" | sed "$r_r"`"
	printf "%s\n" "$s" | sed "s/$p/$r/g"
}

Тестовый набор:

plain_subst 'The quick brown fox jumps over the lazy dog.' 'fox' 'cat'
plain_subst 'The quick brown fox jumps over the lazy dog.' 'fox' 'cat&'
plain_subst 'The quick brown fox jumps over the lazy dog.' 'fox' 'cat\1'
plain_subst 'The quick brown fox jumps over the lazy dog.' 'fox' 'cat/'
plain_subst 'The quick brown fox jumps over the lazy dog.' '.' '!'
plain_subst ',.,' '.' '!'
plain_subst ',.*,' '.*' '!'
plain_subst ',[.],' '[.]' '!'
plain_subst ',^,' '^' '!'
plain_subst ',$,' '$' '!'
На выходе должно быть:
The quick brown cat jumps over the lazy dog.
The quick brown cat& jumps over the lazy dog.
The quick brown cat\1 jumps over the lazy dog.
The quick brown cat/ jumps over the lazy dog.
The quick brown fox jumps over the lazy dog!
,!,
,!,
,!,
,!,
,!,

Deleted

Да уж куда портабельнее. На Linux bash есть, sed то же есть. Можно конечно всё на awk, или perl-е нарисовать.

anonymous
()

Существует ли более простой портабельный (POSIX-совместимый) способ заменить в строке подстроку, чем этот?

конечно: заменить всё это говно одной командой sed.

PS: можно не командой sed, а одним sed скриптом реализовать.

emulek
()
Последнее исправление: emulek (всего исправлений: 1)
# -> text, oldstr, newstr
plain_subst() {
    case "$1" in
        *"$2"*)
            printf '%s%s%s\n' "${1%%"$2"*}" "$3" "${1#*"$2"}" ;;
        *) # no match
            printf '%s\n' "$1"
            return 1 ;;
    esac
}

plain_subst 'The quick brown fox jumps over the lazy dog.' 'fox' 'cat'
plain_subst 'The quick brown fox jumps over the lazy dog.' 'fox' 'cat&'
plain_subst 'The quick brown fox jumps over the lazy dog.' 'fox' 'cat\1'
plain_subst 'The quick brown fox jumps over the lazy dog.' 'fox' 'cat/'
plain_subst 'The quick brown fox jumps over the lazy dog.' '.' '!'
plain_subst ',.,' '.' '!'
plain_subst ',.*,' '.*' '!'
plain_subst ',[.],' '[.]' '!'
plain_subst ',^,' '^' '!'
plain_subst ',$,' '$' '!'
anonymous
()
Ответ на: комментарий от anonymous

Чувак, твоё shell fu сильнее моего! Thanks.

Переделал под рекурсивный вариант для замены всех вхождений:

plain_subst() {
	case "$1" in
		*"$2"*)
			printf '%s%s%s\n' "${1%%"$2"*}" "$3" "`plain_subst "${1#*"$2"}" $2 $3`" ;;
		*) # no match
			printf '%s\n' "$1" ;;
    esac
}
Deleted
()
Ответ на: комментарий от Deleted
`plain_subst "${1#*"$2"}" $2 $3`

`...` (так же, как и $(...)) отрезает все переводы строки на конце.

$2 $3

Без экранирования ("$2" "$3") не будет работать с символами, находящимися в $IFS (обычно это whitespace) и с глоб-символами (*, ?, ...) — при условии, что будут файлы, совпадающие с ними.

plain_subst_global() {
    local s=$1
    while true; do
        case "$s" in
            *"$2"*)
                printf '%s%s' "${s%%"$2"*}" "${3}"
                s=${s#*"$2"} ;;
            *)
                printf '%s\n' "$s"
                break ;;
        esac
    done
}

anonymous
()
Ответ на: комментарий от anonymous

Без экранирования («$2» «$3»)

Эт да, протупил. Детский баг.

`...` (так же, как и $(...)) отрезает все переводы строки на конце.

Ну они мне и не нужны, но т.к. у функции впоследствии могут быть другие пользователи, надо бы исправить на вариант с циклом. Спасибо за замечания.

Deleted
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.