How to get input file name from Unix terminal in C? - c

My program gets executed like:
$./sort 1 < test.txt
sort is the program name
1 is the argument (argv[1])
and test.txt is the file I am inputting from
Is it possible to extract the name file from this? if so how?
The problem is I already wrote my whole program as if I could extract the name from the input line, so I need to be able to pass it into arguments.
Any help is appreciated,
Thanks!

You can't. The shell opens (open(2)) that file and sets up the redirect (most likely using dup2).
The only possible way would be for the shell to explicitly export the information in an environment variable that you could read via getenv.
But it doesn't always make sense. For example, what file name would you expect from
$ echo "This is the end" | ./sort 1

Though this can't be done portably, it's possible on Linux by calling readlink on /proc/self/fd/0 (or /proc/some_pid/fd/0).
eg, running:
echo $(readlink /proc/self/fd/0 < /dev/null)
outputs:
/dev/null

No you can't: the shell sends the content of test.txt to the standard input of your program.
Look at this:
sort << _EOF
3
1
2
_EOF
The < > | operators are processed by the shell, they alter standard input,output,error of the programs in the cmd line.

If you happen to run Solaris, you could parse pfiles output to get the file associated, if any, with stdin.
$ /usr/bin/sleep 3600 < /tmp/foo &
[1] 8430
$ pfiles 8430
8430: /usr/bin/sleep 3600
Current rlimit: 65536 file descriptors
0: S_IFREG mode:0600 dev:299,2 ino:36867886 uid:12345 gid:67890 size=123
O_RDONLY|O_LARGEFILE
/tmp/foo
1: S_IFCHR mode:0600 dev:295,0 ino:12569206 uid:12345 gid:67890 rdev:24,2
...
On most Unix platforms, you will also get the same information from lsof -p if this freeware is installed.

Related

Get the output of multiple strace calls in one file

I want to get the Output of multiple strace calls in one file,
but i do not know how.
At the moment i am using:
strace -o tmpfile, but this just puts the output of one file in and then overrites the file with the new output.
Has anyone an idea, how to do this?
I hope this is no dumb question.
Thanks in advance.
Under the bash shell use the following command
strace -o >(cat >>outputfile) command [args] ...
This will pass to the -o flag an argument that will appear like a file, but will be instead a file descriptor to the standard input of the
cat >>outputfile
process. This process will append its input to the specified output file.
Instead of strace -o somefile command, can you just do strace command >> somefile? Alternatively, assuming a similar version of strace, my manual for strace indicates this should work: strace -o "|tail -a somefile" command (the -o "|command" functionality is implemented by strace itself, not by the shell).
I could not manage to do this via the call itself (in the Android Shell).
I just read through all files and write them to one Log file.
This solution slows the whole process down, but was the only solution I found.
The strace output is on stderr, strace 2>> outfile did the trick for me. If you invoke strace as single command you have to call it like this: adb -e shell "strace -p pid 2>> file"

Stifling "file or directory not found" messages in popen

I'm using popen to run a system script, like so:
snprintf(cmd, MAX_PATH, "/myscript -q | grep -i %s", deviceName);
FILE *res = popen(cmd, "r");
If the script is not found, the program carries on its merry way. However, a "file or directory not found" message is displayed, which seems like an error even though in my intended usage it isn't.
Is there a way to silence this message, or should I just call ls | grep -i myscript before running this line?
Assuming your /bin/sh is a POSIX shell, or a reasonably recent Bourne shell variant, you can redirect standard output within the command before executing the actual command. You only need to prepend exec 2>/dev/null ; before the command you wish to execute.
Here is how I'd personally do this:
/* Shell syntax for redirecting standard error to /dev/null, to
* silence any errors. If /bin/sh does not support this, you can
* simply replace it with an empty string.
*/
#define POPEN_STDERR_NULL "exec 2>/dev/null ;"
...
snprintf(cmd, MAX_PATH, POPEN_STDERR_NULL "/myscript -q | grep -i -e '%s'", deviceName);
FILE *res = popen(cmd, "r");
The popen() command uses /bin/sh internally to run the specified command. The above works for all /bin/sh variants I can test, including Linux and SunOS 5.10, so it should be quite portable. (In other words, dash, bash, and SunOS 5.10 sh all work fine with it.)
Since you'll need to recompile the application for any nonstandard systems, you can always edit the macro to omit the prefix. (You can easily add a test to Makefile magic to automatically omit it if necessary, if you ever find such a system.)
Note that I modified the parameter substitution in the snprintf() call. It will work for any deviceName that does not contain a single quote. Any single quotes in deviceName should be replaced with the string '"'"' before the snprintf() call.
Questions?
I'm not too sure if you can stifle the message. The error is a standard Linux error which is printed onto the standard error stream. You can keep FD '2' which is the file descriptor for Standard error. So maybe you can close this FD.
However, I must warn you that this will prevent any errors from being printed for the rest of your program.
A better way would be to do this:
snprintf(cmd, MAX_PATH, "/myscript -q | grep -i %s 2> dummyfile", deviceName);
This will redirect the error to a dummy file which you delete immediately.
So exercise caution and decide what you would like to do...
Cheers,
VSN

Appending output of a Batch file To log file

I have a batch file which calls a java program.
The output is redirected to a log file in the same directory.
However the log file is replaced everytime the batch file is run...
I would like to keep the old outputs in the log file and always append the new output to the log file.
Instead of using ">" to redirect like this:
java Foo > log
use ">>" to append normal "stdout" output to a new or existing file:
java Foo >> log
However, if you also want to capture "stderr" errors (such as why the Java program couldn't be started), you should also use the "2>&1" tag which redirects "stderr" (the "2") to "stdout" (the "1"). For example:
java Foo >> log 2>&1
This is not an answer to your original question: "Appending output of a Batch file To log file?"
For reference, it's an answer to your followup question: "What lines should i add to my batch file which will make it execute after every 30mins?"
(But I would take Jon Skeet's advice: "You probably shouldn't do that in your batch file - instead, use Task Scheduler.")
Timeout:
timeout command 1
timeout command 2
Example (1 second):
TIMEOUT /T 1000 /NOBREAK
Sleep:
sleep command (if sleep.exe is installed)
Example (1 second):
sleep -m 1000
Alternative methods:
Sleeping in a batch file
batch script, put to sleep until certain time
Here's an answer to your 2nd followup question: "Along with the Timestamp?"
Create a date and time stamp in your batch files
Example:
echo *** Date: %DATE:/=-% and Time:%TIME::=-% *** >> output.log
Use log4j in your java program instead. Then you can output to multiple media, create rolling logs, etc. and include timestamps, class names and line numbers.
It's also possible to use java Foo | tee -a some.log. it just prints to stdout as well. Like:
user at Computer in ~
$ echo "hi" | tee -a foo.txt
hi
user at Computer in ~
$ echo "hello" | tee -a foo.txt
hello
user at Computer in ~
$ cat foo.txt
hi
hello

Shell script to test command line program

I have a program written in C that operates similar to the below output.
WELCOME TO PROGRAM.
Hit 1 to do task 1.
Hit 2 to do task 2.
Hit q to quit.
What i need is a bash shell script that start the program, then enters 1, 2 and q into the program so i can test all the functionality in one command.
I would assume it to look similar to the following
#!/bin/bash
./start kernel
1
2
q
You can use a "here document" . The syntax looks like this:
./start kernel <<EOF
1
2
q
EOF
"EOF" can be whatever unique word you want, as long as it isn't something you'll actually need in the input.
Typically you use expect for testing these types of applications.
You can save your input in a text file - input.txt and execute your program this way: ./program < input.txt
I do this:
#! /bin/bash
printf "1\n2\nq\n" | ./start kernel
You can think of shell scripts as what they are... just each line being executed in an (albeit new) shell.
A simple way to do this sort of input is, assuming [your program] accepts stdin, is:
#!/bin/bash
echo "1" | [your program] > [logfile1]
echo "2" | [your program] > [logfile2]
echo "q" | [your program] > [logfileq]

How to create special files that talk to BASH shell

I'm trying to use someone else's [c] code that controls a linux shell over a wireless usb device. It fopen-s files "IReadFromBash" and "IWriteToBash" in the current dir to communicate. It comes with no notes but obviously expects a special file to already exist to facilitate this, and segfaults without them. Is there some obvious way to create named in- and out-files that connect to a shell?
Really just a guess on my part but I suspect they'll be named pipes, created with mknod. That seems to me the best way to achieve the desired goal.
You can see this in operation here. From a terminal session:
pax> mknod infile p
pax> mknod outfile p
pax> bash <infile >outfile
Then, from another terminal:
pax> echo ls >infile
pax> cat outfile | sed 's/^/ /'
backup0.sh
backup1.sh
Desktop
Downloads
infile
Music
outfile
Pax
Pictures
Public
super_sekrit_porn
Templates
Videos
workspace
pax> _

Resources