Замена с помощью функции sed + bash

мой вопрос кажется общим, но я не могу найти ответы.

В команде sed, как вы можете заменить шаблон замены значением, возвращаемым простой функцией bash.

Например, я создал следующую функцию:

function parseDates(){
    #Some process here with $1 (the pattern found)
    return "dateParsed;
}

и следующая команда sed:

myCatFile=`sed -e "s/[0-3][0-9]\/[0-1][0-9]\/[0-9][0-9]/& parseDates &\}/p" myfile`

Я обнаружил, что символ '&' представляет текущий найденный шаблон, я бы хотел, чтобы он был передан моей функции bash, а весь шаблон был заменен найденным шаблоном +dateParsed.

У кого-нибудь есть идея? Спасибо


person Samir Boulil    schedule 25.04.2011    source источник


Ответы (6)


Вы можете склеить команду sed, завершив раздел в одинарных кавычках и снова открыв его.

sed -n 's|[0-3][0-9]/[0-1][0-9]/[0-9][0-9]|& '$(parseDates)' &|p' datefile

Однако, в отличие от других примеров, функция в bash не может возвращать строки, а только выводить их:

function parseDates(){
    # Some process here with $1 (the pattern found)
    echo dateParsed
}
person user unknown    schedule 25.04.2011
comment
У меня все еще есть проблема с этим решением. Вызывается функция bash. Но аргумент & кажется неправильно скопированным в функции, потому что я не могу использовать $1 в отношении &. - person Samir Boulil; 25.04.2011
comment
О, извините, но приведенное выше решение предназначено для функции, которая не принимает только аргументы и оценивается перед командой sed. Другая возможность состоит в том, чтобы назвать это позже $(script $(sed 'sedcmd' file)) - person user unknown; 25.04.2011

вы можете использовать опцию «e» в команде sed следующим образом:

cat t.sh

myecho() {
        echo ">>hello,$1<<"
}
export -f myecho
sed -e "s/.*/myecho &/e" <<END
ni
END

вы можете увидеть результат без «е»:

cat t.sh

myecho() {
        echo ">>hello,$1<<"
}
export -f myecho
sed -e "s/.*/myecho &/" <<END
ni
END
person xiaofengmanlou    schedule 26.04.2011
comment
вариант «е» не распознается. Также я попытался экспортировать свою функцию через export -f parseDate, что не работает. этот пример не работает для меня. - person Samir Boulil; 26.04.2011
comment
Мне пришлось бросить изменить его на $(myecho) - person Paul Irish; 22.10.2015

Согласен с Гленном Джекманом. Если вы хотите использовать функцию bash в sed, что-то вроде этого:

sed -rn 's/^([[:digit:].]+)/`date -d @&`/p' file |
while read -r line; do
    eval echo "$line"
done

Мой файл здесь начинается с временной метки unix (например, 1362407133.936).

person Antonio    schedule 06.03.2013

делайте это шаг за шагом. (также вы можете использовать альтернативный разделитель, например "|" вместо "/"

function parseDates(){
    #Some process here with $1 (the pattern found)
    return "dateParsed;
}

value=$(parseDates)
sed -n "s|[0-3][0-9]/[0-1][0-9]/[0-9][0-9]|& $value &|p" myfile

Обратите внимание на использование двойных кавычек вместо одинарных, чтобы $value можно было интерполировать.

person ghostdog74    schedule 25.04.2011
comment
Я считаю, что требуется передать совпадающий шаблон в качестве аргумента функции bash. - person Mat; 25.04.2011
comment
dateParsed не нуждается ни в открытии ", ни в закрытии, а вместо return, который может возвращать только int, echo или printf. - person user unknown; 25.04.2011

Я хотел бы знать, есть ли способ сделать это тоже. Однако для этой конкретной задачи он вам не нужен. Если вы окружите различные компоненты даты ()s, вы можете ссылаться на них с помощью \1 \2 и т. д. и переформатировать, как хотите.

Например, давайте перевернем 04.03.1973:

echo 03/04/1973 | sed -e 's/\([0-9][0-9]\)\/\([0-9][0-9]\)\/\([0-9][0-9][0-9][0-9]\)/\3\/\2\/\1/g'
person drysdam    schedule 25.04.2011
comment
Если вы хотите привести в порядок /s в своей команде, sed может принимать символы, отличные от /, для конструкции подстановки (s///), например следующее должно быть эквивалентно вашему примеру: echo 03/04/1973 | sed -e 's#\([0-9][0-9]\)/\([0-9][0-9]\)/\([0-9][0-9][0-9][0-9]\)#\3/\2/\1#g' - person paulw1128; 01.09.2011

Функция Bash внутри sed (возможно, для других целей):

multi_stdin(){ #Makes function accepet variable or stdin (via pipe)
    [[ -n "$1" ]] && echo "$*" || cat -
}

sans_accent(){ 
    multi_stdin "$@" | sed '
        y/àáâãäåèéêëìíîïòóôõöùúûü/aaaaaaeeeeiiiiooooouuuu/
        y/ÀÁÂÃÄÅÈÉÊËÌÍÎÏÒÓÔÕÖÙÚÛÜ/AAAAAAEEEEIIIIOOOOOUUUU/
        y/çÇñÑߢÐð£Øø§µÝý¥¹²³ªº/cCnNBcDdLOoSuYyY123ao/
    '
}

eval $(echo "Rogério Madureira" | sed -n 's#.*#echo & | sans_accent#p')

or

eval $(echo "Rogério Madureira" | sed -n 's#.*#sans_accent &#p')

Rogerio

И если вам нужно сохранить вывод в переменную:

VAR=$( eval $(echo "Rogério Madureira" | sed -n 's#.*#echo & | desacentua#p') )
echo "$VAR"
person Roger    schedule 20.09.2019