8

my question seems to be general, but i can't find any answers.

In sed command, how can you replace the substitution pattern by a value returned by a simple bash function.

For instance, I created the following function :

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

and the folowing sed command :

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

I found that the caracter '&' represents the current pattern found, i'd like it to be passed to my bash function and the whole pattern to be substituted by the pattern found +dateParsed.

Does anybody have an idea ? Thanks

Samir Boulil
  • 83
  • 1
  • 1
  • 3

7 Answers7

4

you can use the "e" option in sed command like this:

cat t.sh

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

you can see the result without "e":

cat t.sh

myecho() {
        echo ">>hello,$1<<"
}
export -f myecho
sed -e "s/.*/myecho &/" <<END
ni
END
  • the option 'e' is not recognized. Also i tried to export my function via export -f parseDate, which is not working. this example doesn't work for me. – Samir Boulil Apr 26 '11 at 10:35
  • I had to toss change it to `$(myecho)` – Paul Irish Oct 22 '15 at 04:28
  • 1
    The `/e` fag is a GNU `sed` extension, and not portable. If your target audience is Linux, you can _probably_ expect them to have GNU `sed` (somewhat also depending on the distro). – tripleee May 16 '22 at 09:11
1

Agree with Glenn Jackman. If you want to use bash function in sed, something like this :

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

My file here begins with a unix timestamp (e.g. 1362407133.936).

Antonio
  • 11
  • 1
1

I'd like to know if there's a way to do this too. However, for this particular problem you don't need it. If you surround the different components of the date with ()s, you can back reference them with \1 \2 etc and reformat however you want.

For instance, let's reverse 03/04/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'
drysdam
  • 8,341
  • 1
  • 20
  • 23
  • If you want to tidy up the /s in your command, sed is able to accept characters other than / for the substitution construct (s///), e.g. the following should be equivalent to your example: `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'` – paulw1128 Sep 01 '11 at 16:16
  • @drysdam You helped me big time with \1 and \2 thing. Cheers. +1 vote – Parth Apr 14 '23 at 13:28
1

Bash function inside sed (maybe for other purposes):

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

And if you need to keep the output into a variable:

VAR=$( eval $(echo "Rogério Madureira" | sed -n 's#.*#echo & | desacentua#p') )
echo "$VAR"
Roger
  • 8,286
  • 17
  • 59
  • 77
0

do it step by step. (also you could use an alternate delimiter , such as "|" instead of "/"

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

Note the use of double quotes instead of single quotes, so that $value can be interpolated

ghostdog74
  • 327,991
  • 56
  • 259
  • 343
  • 1
    I believe that what is requested is for the matched pattern to be passed as an argument to the bash function. – Mat Apr 25 '11 at 10:13
  • 1
    dateParsed needs no opening `"` or a closing one, and instead of "return", which can only return an int, an echo or printf. – user unknown Apr 25 '11 at 11:39
0
sed -e 's#[0-3][0-9]/[0-1][0-9]/[0-9][0-9]#& $(parseDates &)#' myfile |
while read -r line; do
    eval echo "$line"
done
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
-4

You can glue together a sed-command by ending a single-quoted section, and reopening it again.

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

However, in contrast to other examples, a function in bash can't return strings, only put them out:

function parseDates(){
    # Some process here with $1 (the pattern found)
    echo dateParsed
}
user unknown
  • 35,537
  • 11
  • 75
  • 121
  • 1
    I still have a problem with this solution. The bash function is called. But the argument & seems not to be correctly copied In the function because i can't use $1 In reference to &. – Samir Boulil Apr 25 '11 at 12:59
  • 1
    Oh, I'm sorry, but above solution is for a function which doesn't take arguments only, and is evaluated before the sed command. The other possibility is, to call it later `$(script $(sed 'sedcmd' file))` – user unknown Apr 25 '11 at 14:51