I am trying to run C program inside bash, my C program is using the gps device and calculating the distance based on latitude and longitude values. The problem is when i run this C program through bash to get distance, i am not able to redirect its output to any file or variable. i tried this:
output=$(./run)
but it is not working.
to run C code inside bash i am using the following code:
#!/bin/bash
echo 'clear'
echo enter file name
read FILE
gcc -o a.out $FILE -lm
output=$(./a.out)
echo $output
when i do not redirect it shows value:
#!/bin/bash
echo `clear`
echo enter file name
read FILE
gcc -o a.out $FILE -lm
./a.out
[gps values][1]
Can any body help in this?
You don't include the requested debug log, but from your screenshot it looks like your program never exits. It just stays around and writes values forever. Therefore, the capture never reaches the end, so your echo statement never executes.
You should modify your program or invocation so that it will at some point exit.
If you can't modify the program, you can capture e.g. only the first ten lines using one of:
# More canonical way
output=$(./a.out | head -n 10)
# More resilient way, if the program is especially poorly written
output=$( head -n 10 <(./a.out) )
Thank you every one for the comments
It is working now
#!/bin/bash
echo `clear`
echo enter file name
read FILE
gcc -o a.out $FILE -lm
stdbuf -oL ./a.out |
while IFS= read -r line
do
echo "Data: $line"
done
by using the above code
Use -o flag in gcc to create the binary first.
I'll give you an example using "Hello World" code:
~]# cat hw.c
#include <stdio.h>
int main(){
printf("Hello World");
return 0;
}
The bash script:
~]# cat hw.sh
gcc -o hw hw.c
./hw
Then run:
~]# bash hw.sh
Hello World
Related
Using the command line I get the desired output
$ ./program $(< file.txt)
./program 1 2 3 4 5
But with a makefile
all: program file.txt
./program $(< file.txt)
#rm -f program
program: program.c
gcc program.c -o program
I get the output
gcc program.c -o program
./program
Because in a makefile, the $(...) syntax is used for variable interpolation. So your makefile tries to expand the value of a makefile variable / environment variable named < file.txt. And if unset, it expands to an empty string.
Proof:
all:
echo $(< file.txt)
and file.txt containing
now it works
Then execute
% env '< file.txt=Hello world' make
echo Hello world
Hello world
i.e. by setting an environment variable named < file.txt to value Hello world , the greeting was printed. The fix is to escape the $ character by doubling it:
all:
echo $$(< file.txt)
and then
% make
echo $(< file.txt)
now it works
Q.E.D.
Finally, while the $() interpolation syntax in POSIX shells, the $(< file.txt) is not but you can replace it with $(cat file.txt) so it works with minimally POSIX-conforming shells. Of course in a makefile you again need to double the dollar, therefore getting the maximally compatible
$$(cat file.txt)
Alternatively you can use the similar makefile facility which is $(shell ), i.e.
$(shell cat file.txt)
would work too... (now with one $). Finally you can read files with $(file ) GNU makefile function too, i.e.
all:
echo $(file <file.txt)
would work alike but wouldn't call shell at all.
The substitution you are trying to use is a Bash feature, but make out of the box runs the regular Bourne shell sh, where this syntax is not available (even when sh is a symlink to Bash, as is still common on some Linux distributions).
Requiring the contents of the file to be specified on the command line looks like a design flaw, anyway; it's probably much better if your C program simply reads and processes standard input (or perhaps accepts a list of file names, and falls back to stdin if none are specified, like many Unix file processing utilities).
If this is just for a test case to run the program with parameters from a file, check out xargs.
xargs ./program <file.txt
If you insist on using Bash-only syntax, add
SHELL=/bin/bash
(or whatever full path is correct on your system); but understand that this limits the portability of your Makefile.
Still, you'll need to double any literal dollar sign which should be passed through and exposed to the shell.
The below program redirects all my output to log file. I need to display all the output along with log file. How can this be achieved?
$ gcc test.c
$ ./a.out > log.txt
$
You could use tee:
$ ./a.out | tee log.txt
$ cat $HOME/version.txt
version=1.2.3.4
$ cat hello.c
#include <stdio.h>
int main()
{
printf("Software Version = [%s]\n",VERSION);
return 0;
}
$ cat hello.mk
FILE=$(HOME)/version.txt
VERSION:=`cat $(FILE) | cut -d = -f2 | sed -e 's-^-\\\"-g' -e 's-$-\\\"-g'`
compile :
gcc -o hello hello.c -DVERSION=$(VERSION)
$ cat test.sh
FILE=$HOME/version.txt
# Append with \" at the beginning and end of the string for the compiler
cat $FILE | cut -d = -f2 | sed -e 's-^-\\\"-g' -e 's-$-\\\"-g'
OUTPUT of test.sh :
\"1.2.3.4\"
Problem :
I am trying to write a makefile (hello.mk) which reads a static file ($HOME/version.txt) which stores version of the software being developed in the form version=x.x.x.x. Makefile reads the file and extracts the version value and passes to the compile line through -D flag. In the 'C' code (hello.c), printing the VERSION detail. The idea is to just maintain the version file for various builds and the build will have the appropriate version number in various logs etc.,
I wrote a simple script test.sh to test the cut | sed option and it works fine from the command line. When I have them in the makefile as a MACRO, I get syntax error for the last $ sed option. Also, when I use some other hacks to get the values from the file, the compile line -DVERSION=$(VERSION) seem to expand to the macro VERSION commands rather than the actual VERSION value.
To test, in the makefile, if I replace VERSION to hardcode value like \"1.2.3.4\, then the compile goes through with desired effect.
The current format of the version file cannot be changed (legacy code and is used by many other tools).
Appreciate if you could help me to resolve this issue or any better way to parse the file.
You need to escape the $ in sed via $$; Additionally, i've used $(shell ...)
mnunberg#csure:/tmp$ make -f hello.mk
cc -o hello hello.c -DVERSION=\"1.2.3.4\"
mnunberg#csure:/tmp$ ./hello
Hello. Version is 1.2.3.4
mnunberg#csure:/tmp$ cat hello.mk
FILE=version.txt
VERSION:=$(shell cat $(FILE) | cut -d = -f2 | sed -e 's-^-\\\"-g' -e 's-$$-\\\"-g')
compile :
cc -o hello hello.c -DVERSION=$(VERSION)
You need to quote $ as $$ in make shell scripts. I've also trimmed down your pipeline to just use awk.
hello.mk
...
VERSION := $(shell awk '/^version=/ { split($$0, a, /=/); print a[2];}' $(FILE))
compile :
gcc -o hello hello.c -DVERSION='"$(VERSION)"'
Learnt a lot from both your replies. Was not aware of the '"$(VERSION)"' in the compile line. That eliminated the need to append " while parsing. Also, the shell command was cool. Not sure why it is different from when I did a backquotes (‘`’).
Thanks much again.
Did the following for now.
hello.mk ::
VERSION:=$(shell sed -e 's-^version=--g' $(FILE))
....
compile :
gcc -o hello hello.c -DVERSION='"$(VERSION)"'
.....
I wrote this .sh file to compile any c source file, so that when I run it, it asks for a filename and gcc compiles it and then, runs the executable a.out.
But this doesn't work properly when error is present in .c files. It also shows that a.out is not present. I don't want this error message ( a.out is not present ) but just want to print only the error message generated for the .c files..
Here's the script..
echo `clear`
echo enter file name
read FILE
gcc $FILE
./a.out
echo -e '\n'
If you enable abort-on-error in shell scripts, life will be a lot easier:
#!/bin/sh
set -eu # makes your program exit on error or unbound variable
# ...your code here...
Utilizing builtin rules as an alternative to your script you might want to use make as an alternative to a handcrafted script. To compile file.c and run the generated executable all you need to do is:
make file && ./file
If you don't know it, I strongly suggest you take a look at the make utility as it will ease your work a lot. Managing anything more than a one file project can get really nasty without it.
You can chain compilation and execution commands:
echo `clear`
echo enter file name
read FILE
gcc $FILE && ./a.out
echo -e '\n'
Here, if gcc will fail, the shell will drop the ./a.out command.
You may also protect the file name with double quotes :
#! /bin/bash
clear
echo -n "Enter file name: "
read FILE
gcc -Wall -W "$FILE" && ./a.out
echo
I there hope this is what you were looking it only requires this command:
./compile executableName myCProgram.c -lm
you can place more C files ahead of each others and add more libraries at the end of the line and executableName does not require the .exe
#!/bin/bash
args="$#"
quant=$#
#Copies in case you need the -lm(math library) params
biblio=${args#*-}
#grabs all params except the first one which should be the name of the executable
firstCommand=${*:2:${#args}}
#Remove the "-lm -lc" from firstCommand
firstCommand=${firstCommand%%-*}
printf "\nEXECUTING: gcc -W -Wall -c $firstCommand\n"
#Creates the object file ".o"
gcc -W -Wall -c $firstCommand
#Convert the files names from example.c to example.o
args=${args//.c/.o}
printf "\nEXECUTING: gcc -o $args\n\n"
#Creates the executable
gcc -o $args
printf "\n**Now execute comand: ./$1 **\n\n"
Is it possible to compile a stream of data rather than compiling a .c file using gcc? for example, is it possible that instead of having my code stored in any xyz.c file, I can directly compile the code?
Use gcc options -x and -
$ echo -e '#include <stdio.h>\nmain(){puts("Hello world");return 0;}' | gcc -xc -ogarbage - && ./garbage && rm garbage
Hello world
The single line command above is made up of the following parts:
echo -e '#include <stdio.h>\nmain(){puts("Hello world");return 0;}' # "source"
| # pipe
gcc -xc -ogarbage - # compile
&& # and
./garbage # run
&& # and
rm garbage # delete
This may answer you question, though it is rarely useful.
You can create a file, stream the code into it, then create another process(that is, the compiler) giving it the file as an argument. Then create another process(that is, the linker) and it will create an exe for you. And finally you can launch that exe as a new process. But why?!:)