1

I have a file sedstr.sh containing a function sedstr:

#!/bin/bash
function sedstr {
# From stackoverflow.com/a/29626460/633251 (Thanks Ed!)
    old="$1"
    new="$2"
    file="${3:--}"
    escOld=$(sed 's/[^^]/[&]/g; s/\^/\\^/g' <<< "$old")
    escNew=$(sed 's/[&/\]/\\&/g' <<< "$new")
    sed -i.tmp "s/\<$escOld\>/$escNew/g" "$file" # added -i.tmp
    echo "sedstr done"
}

I have an external file "test" to be edited in place with these contents:

My last name is Han.son and I need help.
If the makefile works, I'll have a new last name.

I want to call the sedstr function with its arguments from a makefile. Nothing should be returned, but the external file should be edited. Here is a small makefile that doesn't work:

all: doEdit

doEdit:
  $(shell ./sedstr.sh) # I was hoping this would bring the function into the scope, but nay
  $(shell sedstr 'Han.son', 'Dufus', test)

How can I call this function using variables in the makefile? The error is:

make: sedstr: Command not found
make: Nothing to be done for `all'.
Bryan Hanson
  • 6,055
  • 4
  • 41
  • 78
  • Why have the commands in a function? – Mikkel Christiansen Jul 13 '15 at 01:57
  • @EtanReisner Thank you. The extra `$(shell ... )` was left over from when the line was not in a target. So I removed that and the extra commas (silly), now I have `./sedstr.sh; sedstr 'Hans.son' 'Dufus' test` and it gives the following error: `MWE2:7: *** missing separator. Stop.` With the `$(shell ... )` I get the error I originally reported. – Bryan Hanson Jul 13 '15 at 02:08
  • @MikkelChristiansen Having the function externally was suggested in a another question as a more sensible approach. – Bryan Hanson Jul 13 '15 at 02:09
  • What was the missing separator? – Mikkel Christiansen Jul 13 '15 at 02:28
  • I had used spaces instead of tab (obviously new to this). – Bryan Hanson Jul 13 '15 at 02:29
  • sed might not use \< and \>. It isn't standard regex. – Mikkel Christiansen Jul 13 '15 at 02:55
  • Hmm... I got the function [here](http://stackoverflow.com/a/29626460/633251) but I just tested it with the example at that page, and it doesn't seem to work in my context. I need to regroup and make sure I'm doing everything correctly. Thanks for your help. – Bryan Hanson Jul 13 '15 at 03:04
  • You noticed that you have `Han.son` in the file but `'Hans.son'` in the makefile snippet? Also your edit to `sedstr` to make it a function complicates the usage in a makefile where using it as a script would be simpler (no sourcing required first). – Etan Reisner Jul 13 '15 at 12:49
  • @EtanReisner Yes, another sharp-eyed person caught that typo but that isn't the problem (I'll edit the question). Thank you. Right now I think I have the call to the function working correctly but it may be that the function itself is not working - I need to investigate further. – Bryan Hanson Jul 13 '15 at 13:48
  • The function works. I tested both the original and your version on your test file. – Etan Reisner Jul 13 '15 at 15:40

2 Answers2

3

Each line in a make recipe is executed in its own shell.

Similarly, so is each call to $(shell).

They don't share state.

To do what you want ould would need a recipe line of

$(shell . ./sedstr.sh; sedstr 'Han.son' 'Dufus' test)

That being said there's no reason to use $(shell) here at all as you are already in a shell context and as you can just as easily (and more correctly) use a recipe line of

. ./sedstr.sh; sedstr 'Hans.son' 'Dufus' test

And yes, the commas in the original are just incorrect.

Bryan Hanson
  • 6,055
  • 4
  • 41
  • 78
Etan Reisner
  • 77,877
  • 8
  • 106
  • 148
  • Thanks for the advice on the 'big picture'. If I use the direct approach, it complains `/bin/sh: sedstr: command not found` which is not the shell I thought I was using... – Bryan Hanson Jul 13 '15 at 02:42
  • make uses `/bin/sh` by default but that's not really relevant here. The second attempt here had a typo, you need to source the script and not run it as a script on its own. – Etan Reisner Jul 13 '15 at 03:10
  • Got it, error eliminated, but it doesn't carry out the editing. I'm doubting the function now, see my comments above under the original question. Thanks for you help. – Bryan Hanson Jul 13 '15 at 03:20
  • I got it working now. No problem with the sedstr function. Seemed to be a problem with crossing my test functions and test files, and also, unsaved edits were not being seen in testing. Thanks for your help. – Bryan Hanson Jul 13 '15 at 14:42
  • Final question: In `. ./sedstr.sh; ...` what does the first `.` do? – Bryan Hanson Jul 13 '15 at 14:43
  • `source`/`.` loads a script file in the current session. – Etan Reisner Jul 13 '15 at 15:40
  • But doesn't `./sedstr.sh` do that? I'm still confused about the leading `.` Unfortunately this stuff is sort of hard to look up! – Bryan Hanson Jul 13 '15 at 16:59
  • 1
    No, `./sedstr.sh` runs the script as a script. So the function only exists in the shell context of the script that ends immediately when the file ends. `.` loads the script in the *current* shell context. Look for `source` in the bash man page. – Etan Reisner Jul 13 '15 at 17:04
1

You can call the function from inside sedstr.sh. At the end

sedstr "$1" "$2" "$3"

EDIT Or see other answer