force variable evaluation within Makefile - sed

In one of my Makefiles, a variable receives a value determined by a sed script :
VAR_SCRIPT:=`sed -n '/expression/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < file.h`
The sed script will find the appropriate value within file.h.
It works fine. Later on this value is used to create versioned file names.
But in fact, the sed program is not evaluated at the moment VAR_SCRIPT is created. It keeps its script format all along, and is only evaluated at the last moment.
This cause problems in later parts of the Makefile. Typically, I would like the result of VAR_VALUE later on in another sed script, not the script formula itself.
Trying to transfer the value of the sed script through :
VAR_VALUE := $(VAR_SCRIPT)
only transfers the script, not the result of the script.
How to force evaluation of the sed script ?
Edit : one solution found :
VAR_VALUE := $(shell echo $(VAR_SCRIPT))
See also #Andrey suggestion

You can try shell function:
VARIABLE := $(shell command)
For example, check this Makefile (no tabs):
C := sed -n 'p' <<< 'test'
V := $(shell $(C))
all: ; #echo $(V)

Related

Pass file name as a string through command line into Maple

I'm trying to use Maple function in external program using command-line interface. Data for function is to be passed through file. For demonstration of the problem I created two files: /home/user_name/test.mpl and /home/user_name/test_data.txt.
test.mpl ("cat" demonstrates use of Maple function):
#filename := "/home/user_name/test_data.txt":
print(filename):
i := parse(readline(filename)):
poly := parse(readline(filename)):
s := parse(readline(filename)):
print(cat(convert(poly+i,string), " ", s)):
test_data.txt :
1
x^2 * y + 1
"A string."
According to the manual, I can use something like this (but this example doesn't cover usage of two files, one as a code and another as an argument):
/usr/local/maple/bin/maple -c 'datafile:="/tmp/12345.data";' -c N:=1;
When I try
/path/to/maple -c 'filename:="/home/user_name/test_data.txt":' -q /home/user_name/test.mpl
I get the following error:
Error, incorrect syntax in parse: `/` unexpected (near 11th character of parsed string)
If I delete first / in filename string, I get the following output (before the errors related to readline):
/ home \
|-------------------| . txt
\user_name test_data/
It clearly demonstrates that file path is not parsed as a string (but probably as some kind of expression). Probably I should use some escape sequences, for Maple or for shell, but none of my attempts worked.
If I get file name inside test.mpl (uncommenting first line there and removing -c parameter), it works though, but that's not what I need.
How to pass file name as a string through command line (probably not with using -c)?
It works for me using commandline Maple on Linux, as say,
/path/to/maple -c 'filename:=\"/home/user_name/test_data.txt\":' -q /home/user_name/test.mpl

Read command output line by line in sh (no bash)

I am basically looking for a way to do this
list=$(command)
while read -r arg
do
...
done <<< "$list"
Using sh intead of bash. The code as it is doesn't run because of the last line:
syntax error: unexpected redirection
Any fixes?
Edit: I need to edit variables and access them outside the loop, so using | is not acceptable (as it creates a sub-shell with independent scope)
Edit 2: This question is NOT similar to Why does my Bash counter reset after while loop as I am not using | (as I just noticed in the last edit). I am asking for another way of achiving it. (The answers to the linked question only explain why the problem happens but do not provide any solutions that work with sh (no bash).
There's no purely syntactic way to do this in POSIX sh. You'll need to use either a temporary file for the output of the command, or a named pipe.
mkfifo output
command > output &
while read -r arg; do
...
done < output
rm output
Any reason you can't do this? Should work .. unless you are assigning any variables inside the loop that you want visible when it's done.
command |
while read -r arg
do
...
done

sed command is not working properly

I'm trying to replace the word in shell script with sed -e command but its not replacing , please help on that, i have tried the below
we have separate file in /data/docs/config.log, in that file there is a word ?account for example ,
username acc, passsword acc, ?account.name
this ?account word needs to be replaced with word 'GLOBAL' using sed -e command ,
reacc = GLOBAL
sed -e "s/?account/$reacc/g" /data/docs/config.log > /data/docs/newconfig.log
but here the file newconfig.log has created with 0 size , no output written to the file , its not replacing its an empty file,
the output should be username acc, passsword acc, GLOBAL.name in newconfig.log
Being the only person who can reproduce the problem, you are pretty much on your own. There are plenty of things you can do to analyze the problem, though.
Double-check the shell. Don't have blind faith in #!/bin/sh. In cygwin for example, /bin/sh is an alias for bash. Verify with: echo $SHELL
Check permissions and file system. Do you have rights to write to the output file? Is the disk full? Does cat /data/docs/config.log > /data/docs/newconfig.log work? Test again in a different folder.
Double-check the output file. Is it really empty, or is the file system just slow with updating the file size? Is sed really finished? Test without output redirection; see if the output is dumped to stdout.
Test with a small file; one or two lines is enough.
If even that does not work, then test sed itself. Who knows, maybe you have a weird alias that hides the real sed. The most trivial filter is sed -e '', which should simply echo every line you type (just like cat without parameters). Does that work? Then try some simple patterns.
Systematically iterate between test cases that succeed and test case that fail, until you have found the breaking point. Doing so, you should be able to find the cause. Sorry, that's all I can do for you right now.
Remove spaces around =. Try after making
reacc=GLOBAL

Need to convert ksh command line to sh

I'm trying to do a simple operation in ksh that I need to repeat in sh (Bourne shell)
All I want to do is append the contents of the first line of hte pay_period.txt file to the end of the new file name. This works great in ksh, but does not work in bourne. The program I'm using defaults to sh and I can't change that. Also I can't have actual shell scipts in the directories. So I have to issue commands.
How can I make the equivalent command below work in bourne
mv HEPAY.txt HE_PAY"$(/usr/bin/head -1 pay_period.txt)."txt
The results of $(/usr/bin/head -1 pay_period.txt) is 20140101.
If you are really talking about a real Bournce shell then you need to use backticks for command substitution ($() is POSIX and portable among "modern", POSIX-compliant shells but won't work in old, legacy shells), e.g.
mv HEPAY.txt HE_PAY`/usr/bin/head -1 pay_period.txt`.txt
Other than that I see no reason why this should not work.
PS: Note that head -1 isn't POSIX-compliant either (head -n 1 is).

cygwin sed substitution against commands in history

I couldn't find an answer for this exact problem, so I'll ask it.
I'm working in Cygwin and want to reference previous commands using !n notation, e.g., if command 5 was which ls, then !5 runs the same command.
The problem is when trying to do substitution, so running:
!5:s/which \([a-z]\)/\1/
should just run ls, or whatever the argument was for which for command number 5.
I've tried several ways of doing this kind of substitution and get the same error:
bash: :s/which \([a-z]*\)/\1/: substitution failed
As far as I can tell the s/old/new/ history substitution syntax only does simple string substitution; it does not support full regexes. Here's what man bash has to say:
s/old/new/
Substitute new for the first occurrence of old in the event line. Any delimiter can be used in place of /. The final delimiter is optional if it is the last character of the event line. The delimiter may be quoted in old and new with a single backslash. If & appears in new, it is replaced by old. A single backslash will quote the &. If old is null, it is set to the last old substituted, or, if no previous history substitutions took place, the last string in a !?string[?] search.
Never fear, though. There are in fact easier ways to accomplish what you are trying to do:
!$ evaluates to the last argument of the previous command:
# ls /etc/passwd
/etc/passwd
# vim !$
vim /etc/passwd
!5:$ evaluates to the last argument of command #5:
# history
...
5: which ls
...
# !5:$
ls
You can also use Alt+. to perform an immediate substitution equivalent to !$. Alt+. is one of the best bash tricks I know.
This worked for me using Bash in Cygwin (note that my which ls command was number 501 in my history list; not 5 like yours):
$(!501 | sed 's/which \([a-z]\)/\1/')
You could also do it this way (which is shorter/cleaner):
$(!501 | sed 's/which //')