My program accepts many options.
And I have to write a shell script to test my program.
The shell script must run my program multiple times and every time it must pass different options and different arguments for an option.
For example:
#!/bin/bash
echo "CS111 " > testing.txt
echo "is " >> testing.txt
echo "intersting " >> testing.txt
echo "even " >> testing.txt
echo "though " >> testing.txt
echo "it " >> testing.txt
echo "is " >> testing.txt
echo "time " >> testing.txt
echo "consuming " >> testting.txt
echo "and " >> testing.txt
echo "hard " >> testing.txt
./simpsh \
--verbose \
--rdonly in.txt \
--append --wronly out.txt \
--wronly err.txt \
--command 0 1 2 sort testing
./simpsh \
--verbose\
--rdonly in.txt \
--append --wronly out.txt \
--wronly err.txt \
--command 0 1 2 sort
The first test will be executed, but then there is an error 127.
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
int main(int argc, char **argv)
{
int c;
int oflag = 0;
int *fd;
int fdCount = 0;
int pipefd[2];
int p;
int verbose = 0;
while (1) {
static struct option long_options[] = {
{"append",no_argument,0,'a'},
{"cloexec",no_argument,0,'b'},
{"creat", no_argument,0,'c'},
{"directory",no_argument,0,'d'},
{"dsync",no_argument,0,'e'},
{"excl",no_argument,0,'f'},
{"nofollow",no_argument,0,'g'},
{"nonblock",no_argument, 0,'h'},
{"rsync",no_argument,0,'i'},
{"sync",no_argument,0,'j'},
{"trunc",no_argument,0,'k'},
{"rdonly",required_argument,0,'l'},
{"rdwr",required_argument,0,'m'},
{"wronly",required_argument,0,'n'},
{"pipe",no_argument,0,'o'},
{"command",required_argument,0,'p'},
{"wait",no_argument,0,'q'},
{"close",required_argument,0,'r'},
{"verbose",no_argument,0,'s'},
{"profile",no_argument,0,'t'},
{"abort",no_argument,0,'u'},
{"catch",required_argument,0,'v'},
{"ignore",required_argument,0,'w'},
{"default",required_argument,0,'x'},
{"pause",no_argument,0,'y'},
};
c = getopt_long(argc, argv, "abcdefghijkl:m:n:op:qr:stuv:w:x:y", long_options, NULL);
if (c == -1)
break;
switch (c) {
case 'a':
if(verbose)
printf("O_APPEND\n");
oflag = oflag | O_APPEND;
break;
case 'b':
if(verbose)
printf("O_CLOEXEC\n");
oflag = oflag | O_CLOEXEC;
break;
case 'c':
if(verbose)
printf("O_CREAT\n");
oflag = oflag | O_CREAT;
break;
case 'd':
if(verbose)
printf("O_DIRECTORY\n");
oflag = oflag | O_DIRECTORY;
break;
case 'e':
if(verbose)
printf("O_DSYNC\n");
oflag = oflag | O_DSYNC;
break;
case 'f':
if(verbose)
printf("O_EXCL\n");
oflag = oflag | O_EXCL;
break;
case 'g':
if(verbose)
printf("O_NOFOLLOW\n");
oflag = oflag | O_NOFOLLOW;
break;
case 'h':
if(verbose)
printf("O_NONBLOCK\n");
oflag = oflag | O_NONBLOCK;
break;
case 'i':
if(verbose)
printf("O_RSYNC\n");
oflag = oflag | O_RSYNC;
break;
case 'j':
if(verbose)
printf("O_SYNC\n");
oflag = oflag | O_SYNC;
break;
case 'k':
if(verbose)
printf("O_TRUNC\n");
oflag = oflag | O_TRUNC;
break;
case 'l':
if(optarg){
if(fdCount == 0)
fd = (int *)malloc(sizeof(int));
else
fd = (int *)realloc(fd, (fdCount + 1)* sizeof(int));
if(verbose)
printf("O_RDONLY %s\n", optarg);
fd[fdCount] = open(optarg, oflag | O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
oflag = 0;
if(fd[fdCount] == -1){
fprintf(stderr, "%s cannot be opened/created", optarg);
exit(1);
}
else
fdCount++;
}
break;
case 'm':
if(optarg){
if(fdCount == 0)
fd = (int *)malloc(sizeof(int));
else
fd = (int *)realloc(fd, (fdCount + 1)* sizeof(int));
if(verbose)
printf("O_RDWR %s\n", optarg);
fd[fdCount] = open(optarg, oflag | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO);
oflag = 0;
if(fd[fdCount] == -1){
fprintf(stderr, "%s cannot be opened/created", optarg);
exit(2);
}
else
fdCount++;
}
break;
case 'n':
if(optarg){
if(fdCount == 0)
fd = (int *)malloc(sizeof(int));
else
fd = (int *)realloc(fd, (fdCount + 1)* sizeof(int));
if(verbose)
printf("O_WRONLY %s\n", optarg);
fd[fdCount] = open(optarg, oflag | O_WRONLY, S_IRWXU | S_IRWXG | S_IRWXO);
oflag = 0;
if(fd[fdCount] == -1){
fprintf(stderr, "%s cannot be opened/created", optarg);
exit(3);
}
else
fdCount++;
}
break;
case 'o':
if(verbose)
printf("pipe\n");
p = pipe(pipefd);
if(p == -1){
fprintf(stderr, "The pipe wasn't made.\n");
exit(5);
}
else{
if(fdCount == 0)
fd = (int *)malloc(2 * sizeof(int));
else
fd = (int *)realloc(fd, (fdCount + 2) * sizeof(int));
fdCount = fdCount + 2;
fd[fdCount - 2] = pipefd[0];
fd[fdCount - 1] = pipefd[1];
}
break;
case 'p':
if(optarg){
if(verbose){
printf("command ");
int vi = optind -1;
for( vi = optind - 1; vi < argc && *argv[vi] != '-'; vi++)
printf("%s ", argv[vi]);
printf("\n");
}
pid_t pid = fork();
if(pid == 0){
int fdin;
int fdout;
int fderr;
int i = 0;
char **arg;
int index;
for(index = optind-1; index < argc && *argv[index] != '-'; index++, i++){
switch(i){
case 0:
fdin = atoi(argv[index]);
break;
case 1:
fdout = atoi(argv[index]);
break;
case 2:
fderr = atoi(argv[index]);
break;
default:
if(i - 3 == 0)
arg = (char**)malloc(sizeof(char));
else
arg = (char**)realloc(arg, ((i - 3) + 1)* sizeof(char));
arg[i - 3] = strdup(argv[index]);
}
}
dup2(fd[fdin],0);
close(fd[fdin]);
dup2(fd[fdout],1);
close(fd[fdout]);
dup2(fd[fderr],2);
close(fd[fderr]);
execvp(arg[0], arg);
}
else if(pid == -1){
fprintf(stderr, "The new proccess isn't created by fork()\n");
exit(6);
}
}
break;
case 'q':
break;
case 'r':
break;
case 's':
verbose = 1;
break;
case 't':
break;
case 'u':
break;
case 'v':
break;
case 'w':
break;
case 'x':
break;
case 'y':
break;
default:
fprintf(stderr, "An option is misstyped or has no argument\n");
exit(4);
}
}
exit(0);
}
Return code 127 indicates the command was not found.
It is likely myprogram is not found inside the current directory you execute your test script from.
Try changing to the directory where your program is located, or calling it with a full path.
Also, remember bash ignores commands that fail unless you activate the "-e" flag or trap errors and handle them explicitly. When building a test script (or any script for that matter), allowing silent failure could lead to bad surprises down the road.
Related
Many times I have typical ETL code that looks like this
./call_some_api.py | ./extract_transform | ./load_to_some_sql
What if either of the first two scripts stop sending bytes because of some internal error that causes them to stall. I wish there was another program I could put before ./load_to_some_sql that will detect that 0 bytes has been sent in 5 minutes, and throw an exit code.
Curl has --speed-limit and --speed-time which do exactly this, but it's not generalized for other cli apps.
Is there a way to do this? Have a way to crash if the throughput hits a certain level on a pipe?
I know state machines and other orchestration tools can do this, but in general if there's a way to do it from bash it would be helpful!
If you are interested in inactivity timeout, these can do it.
One liner (mentioned in comments). Adjust $t for inactivity seconds:
perl -e'$t=300;$SIG{ALRM}=sub{die"Timeout\n"};alarm$t;while(<>){print;alarm$t}'
More robust:
#include <sys/epoll.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>
long secs = 300;
int stdin_mode, stdout_mode;
void my_exit(int code) {
fcntl(STDIN_FILENO, F_SETFL, stdin_mode);
fcntl(STDOUT_FILENO, F_SETFL, stdout_mode);
exit(code);
}
char* progname = "";
void perror_die(char* msg) {
dprintf(STDERR_FILENO, "%s: %s: %m\n", progname, msg);
my_exit(EXIT_FAILURE);
}
int check(int ret, char *msg) {
if (ret == -1) perror_die(msg);
return ret;
}
void usage() {
dprintf(STDERR_FILENO, "Usage:\n-s <secs> inactivity timeout in seconds (default: %ld seconds)\n", secs);
exit(EXIT_SUCCESS);
}
int main(int argc, char* argv[]) {
progname = argv[0];
signal(SIGHUP, SIG_IGN);
stdin_mode = fcntl(STDIN_FILENO, F_GETFL);
stdout_mode = fcntl(STDOUT_FILENO, F_GETFL);
int opt;
while((opt = getopt(argc, argv, "s:h")) != -1)
switch(opt) {
case 's':
secs = strtol(optarg, NULL, 10);
break;
case 'h':
case '?':
usage();
};
if (optind < argc) usage();
int epfd = check(epoll_create(3), "epoll_create");
struct epoll_event ev = {
.events = EPOLLIN | EPOLLET,
.data.fd = STDIN_FILENO
};
check(epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev), "epoll_ctl");
check(fcntl(STDIN_FILENO, F_SETFL, stdin_mode | O_NONBLOCK), "fcntl stdin");
ev.events = 0;
ev.data.fd = STDOUT_FILENO;
int epout = !epoll_ctl(epfd, EPOLL_CTL_ADD, STDOUT_FILENO, &ev);
if (epout)
check(fcntl(STDOUT_FILENO, F_SETFL, stdout_mode | O_NONBLOCK), "fcntl stdout");
char buf[4096];
ssize_t b_read = 0, b_wrote = 0, bytes = 0;
secs *= 1000;
int epres;
while((epres = epoll_wait(epfd, &ev, 1, secs)) == 1) {
if (ev.events & EPOLLERR) {
errno = EPIPE;
break;
}
for(;;) {
if (b_read == 0) {
b_read = read(STDIN_FILENO, buf, sizeof(buf));
if (b_read > 0) bytes += b_read;
else if (b_read == -1) {
if (errno == EAGAIN) {
b_read = 0;
break;
} else perror_die("read");
} else my_exit(EXIT_SUCCESS);
}
if (b_read) {
int w = write(STDOUT_FILENO, buf + b_wrote, b_read - b_wrote);
if (w != -1) b_wrote += w;
else {
if (errno == EAGAIN && epout) {
ev.events = EPOLLOUT | EPOLLONESHOT;
ev.data.fd = STDOUT_FILENO;
check(epoll_ctl(epfd, EPOLL_CTL_MOD, STDOUT_FILENO, &ev), "epoll_ctl");
break;
} else perror_die("write");
}
if (b_wrote == b_read) b_read = b_wrote = 0;
}
}
}
if (epres) perror_die("event loop");
dprintf(STDERR_FILENO, "%s: Timeout reached\n", progname);
my_exit(EXIT_FAILURE);
}
If you are interested in measuring bytes/secs this can do it, on an interval: (calculation could be improved to keep last n secs bandwidth instead of an interval)
#include <sys/epoll.h>
#include <fcntl.h>
#include <sys/timerfd.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>
ssize_t min_bw = 1000;
long secs = 5;
int stdin_mode, stdout_mode;
void my_exit(int code) {
fcntl(STDIN_FILENO, F_SETFL, stdin_mode);
fcntl(STDOUT_FILENO, F_SETFL, stdout_mode);
exit(code);
}
char* progname = "";
void perror_die(char* msg) {
dprintf(STDERR_FILENO, "%s: %s: %m\n", progname, msg);
my_exit(EXIT_FAILURE);
}
int check(int ret, char *msg) {
if (ret == -1) perror_die(msg);
return ret;
}
void usage() {
dprintf(STDERR_FILENO, "Usage:\n-b <bytes> minimum bytes per (default: %ld bytes)\n-s <secs> seconds (default: %ld seconds)\n", min_bw, secs);
exit(EXIT_SUCCESS);
}
int main(int argc, char* argv[]) {
progname = argv[0];
signal(SIGHUP, SIG_IGN);
stdin_mode = fcntl(STDIN_FILENO, F_GETFL);
stdout_mode = fcntl(STDOUT_FILENO, F_GETFL);
int opt;
while((opt = getopt(argc, argv, "b:s:h")) != -1)
switch(opt) {
case 'b':
min_bw = strtol(optarg, NULL, 10);
break;
case 's':
secs = strtol(optarg, NULL, 10);
break;
case 'h':
case '?':
usage();
};
if (optind < argc) usage();
int epfd = check(epoll_create(3), "epoll_create");
int tmfd = check(timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK), "timerfd_create");
struct itimerspec when = {{secs, 0}, {secs, 0}};
check(timerfd_settime(tmfd, 0, &when, NULL), "timerfd_settime");
struct epoll_event ev = {
.events = EPOLLIN | EPOLLET,
.data.fd = tmfd
};
check(epoll_ctl(epfd, EPOLL_CTL_ADD, tmfd, &ev), "epoll_ctl");
ev.data.fd = STDIN_FILENO;
check(epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev), "epoll_ctl");
check(fcntl(STDIN_FILENO, F_SETFL, stdin_mode | O_NONBLOCK), "fcntl stdin");
ev.events = 0;
ev.data.fd = STDOUT_FILENO;
int epout = !epoll_ctl(epfd, EPOLL_CTL_ADD, STDOUT_FILENO, &ev);
if (epout)
check(fcntl(STDOUT_FILENO, F_SETFL, stdout_mode | O_NONBLOCK), "fcntl stdout");
char tmbuf[64];
char buf[4096];
ssize_t b_read = 0, b_wrote = 0, bytes = 0;
int epres;
while((epres = epoll_wait(epfd, &ev, 1, -1)) == 1) {
if (ev.events & EPOLLERR) {
errno = EPIPE;
break;
}
if (ev.data.fd == tmfd) {
if (bytes < min_bw) {
dprintf(STDERR_FILENO, "Too slow\n");
my_exit(EXIT_FAILURE);
}
check(read(tmfd, tmbuf, sizeof(tmbuf)), "read timerfd");
bytes = 0;
continue;
}
for(;;) {
if (b_read == 0) {
b_read = read(STDIN_FILENO, buf, sizeof(buf));
if (b_read > 0) bytes += b_read;
else if (b_read == -1) {
if (errno == EAGAIN) {
b_read = 0;
break;
} else perror_die("read");
} else my_exit(EXIT_SUCCESS);
}
if (b_read) {
int w = write(STDOUT_FILENO, buf + b_wrote, b_read - b_wrote);
if (w != -1) b_wrote += w;
else {
if (errno == EAGAIN && epout) {
ev.events = EPOLLOUT | EPOLLONESHOT;
ev.data.fd = STDOUT_FILENO;
check(epoll_ctl(epfd, EPOLL_CTL_MOD, STDOUT_FILENO, &ev), "epoll_ctl");
break;
} else perror_die("write");
}
if (b_wrote == b_read) b_read = b_wrote = 0;
}
}
}
perror_die("event loop");
}
Both programs are for linux only.
Provided you have a newish version of Bash, the read builtin can optionally enforce a timeout [docs], which means that it's actually not hard to write a bit of pure Bash code that does exactly what you describe:
... upstream command ... \
| {
while true ; do
read -r -N 1 -t 300 char
result=$?
if (( result > 128 )) ; then
echo 'Read timed out.' >&2
exit 1
elif (( result > 0 )) ; then
exit 0
elif [[ "$char" == '' ]] ; then
printf '\0'
else
printf %s "$char"
fi
done
} \
| ... downstream command ...
(Note: the above reads one character at a time for simplicity's sake; if you expect a high volume of data to pass through this, then you may need to adjust it for better performance.)
But even though the above does exactly what you describe, I'm not sure whether it will really accomplish your goal, because the upstream command won't actually die until it tries to write something and gets SIGPIPE. So even after the above prints Read timed out, Bash will just keep hanging indefinitely, probably until the user hits Ctrl-C. (The same goes for niry's answer, of course.) That's a bit harder to fix; I guess when your command detects a timeout, it will need to find the process-IDs of the upstream commands, and use kill to proactively send them SIGPIPE (or some other signal of your choosing)?
I'm trying to get the original destination of UDP packet using IP_ORIGDSTADDR. On older kernel that mine, it seems to work (I'm running the currently debian testing kernel, 4.7.0-1-amd64).
#define _DEFAULT_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define DEFAULT_ADDR "127.0.0.1"
#define DEFAULT_PORT 6666
int main(int ac, char **av)
{
int sock;
struct sockaddr_in sin;
memset(&sin, 0, sizeof sin);
sin.sin_family = AF_INET;
if (inet_aton(ac >= 2 ? av[1] : DEFAULT_ADDR, &sin.sin_addr) < 0) {
fprintf(stderr, "Invalid address\n");
goto err;
}
sin.sin_port = htons(ac >= 3 ? atoi(av[2]) : DEFAULT_PORT);
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("socket");
goto err;
}
if (bind(sock, (struct sockaddr *) &sin, sizeof sin) < 0) {
perror("bind");
goto close_err;
}
#define SOCK_OPT(l, n, v) do { \
int _v = v; \
socklen_t _s; \
if (setsockopt(sock, l, n, &_v, sizeof _v) < 0) { \
perror("setsockopt "# l "/" # n); \
goto close_err; \
} \
\
_s = sizeof (_v); \
if (getsockopt(sock, l, n, &_v, &_s) < 0) { \
perror("getsockopt "# l "/" # n); \
goto close_err; \
} \
\
if (_v != v) { \
fprintf(stderr, "Unexpected sockopt (expected %d, found %d)\n", v, _v); \
goto close_err; \
} \
\
printf(#l "/" #n " is set to %d\n", _v); \
\
} while (0)
SOCK_OPT(SOL_IP, IP_RECVORIGDSTADDR, 1);
SOCK_OPT(SOL_IP, IP_RECVOPTS, 1);
SOCK_OPT(SOL_IP, IP_PKTINFO, 1);
#undef SOCK_OPT
printf("Reading on %s:%d\n", inet_ntoa(sin.sin_addr), htons(sin.sin_port));
for (;;) {
ssize_t n;
char buf[1024];
char tmp[80];
struct iovec iovec[] = {
{
.iov_base = buf,
.iov_len = sizeof buf - 1,
}
};
struct msghdr msghdr;
struct cmsghdr *cmsg_ptr;
struct sockaddr_storage from = { 0 };
int port;
union cmsg_data {
struct sockaddr_in sin;
struct in_pktinfo pktinfo;
};
char msg_control[CMSG_SPACE(sizeof(union cmsg_data)) * 10] = { 0 };
int found;
memset(&msghdr, 0, sizeof msghdr);
msghdr.msg_name = &from;
msghdr.msg_namelen = sizeof from;
msghdr.msg_iov = iovec;
msghdr.msg_iovlen = sizeof iovec / sizeof iovec[0];
msghdr.msg_control = msg_control;
msghdr.msg_controllen = sizeof msg_control;
msghdr.msg_flags = MSG_EOR | MSG_TRUNC | MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE;
n = recvmsg(sock, &msghdr, MSG_OOB);
if (n < 0) {
perror("recvmsg");
continue;
}
if (buf[n - 1] == '\n')
n--;
buf[n] = 0;
switch (from.ss_family) {
default:
tmp[0] = 0;
break;
case AF_INET:
inet_ntop(AF_INET, &((struct sockaddr_in *) &from)->sin_addr, tmp, sizeof tmp);
port = htons(((struct sockaddr_in *) &from)->sin_port);
break;
case AF_INET6:
inet_ntop(AF_INET6, &((struct sockaddr_in6 *) &from)->sin6_addr, tmp, sizeof tmp);
port = htons(((struct sockaddr_in6 *) &from)->sin6_port);
break;
}
printf("%s:%d Rx %ldb: %.*s, msg_control = %zdb\n", tmp, port, n, (int) n, buf, sizeof msg_control);
found = 0;
for (cmsg_ptr = CMSG_FIRSTHDR(&msghdr); cmsg_ptr != NULL; cmsg_ptr = CMSG_NXTHDR(&msghdr, cmsg_ptr)) {
union cmsg_data *cmsg_data = (union cmsg_data *) CMSG_DATA(cmsg_ptr);
switch (cmsg_ptr->cmsg_level) {
default:
fprintf(stderr, "Unexecpted level : %d\n", cmsg_ptr->cmsg_level);
break;
case SOL_IP:
switch (cmsg_ptr->cmsg_type) {
default:
fprintf(stderr, "Unexecpted type : %d\n", cmsg_ptr->cmsg_type);
break;
case IP_ORIGDSTADDR:
printf("IP_ORIGDSTADDR: sin_addr = %s, sin_port = %d\n", inet_ntoa(cmsg_data->sin.sin_addr), htons(cmsg_data->sin.sin_port));
found++;
break;
case IP_PKTINFO:
snprintf(tmp, sizeof tmp, "%s", inet_ntoa(cmsg_data->pktinfo.ipi_spec_dst));
printf("IP_PKTINFO: ifindex = %u, spec_dst = %s, addr = %s\n", cmsg_data->pktinfo.ipi_ifindex, tmp, inet_ntoa(cmsg_data->pktinfo.ipi_addr));
break;
}
}
}
if (found != 1)
fprintf(stderr, "*** Warning: No SOL_IP / IP_ORIGDSTADDR found\n");
}
close_err:
close(sock);
err:
return 1;
}
When trying this bunch of code (eg. sending packets using netcat), I dont have any IP_ORIGDSTADDR, but only IP_PKTINFO : I need to have UDP port, only IP_ORIGDSTADDR can provide it.
Does anyone have met this strange behaviour ?
I want to make a shell that can use pipes. When I use this code to run a pipe in my shell even though everything is in a WHILE(1) loop my shell terminates. Why? Is there a problem with the use of the dup function?
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
int main(void)
{
int pfds[2];
pipe(pfds);
char *ar1;
const char sp = ' ';
int temp, temp1, temp2, acc;
int i, j;
int t = 0;
char *line=(char *) malloc(1024*sizeof(char));
char *frsarg=(char *) malloc(1024*sizeof(char));
char *firstcmd=(char *) malloc(1024*sizeof(char));
char *seccmd=(char *) malloc(1024*sizeof(char));
char *scmd=(char *) malloc(1024*sizeof(char));
char *secondcmd=(char *) malloc(1024*sizeof(char));
char *secarg=(char *) malloc(1024*sizeof(char));
char *frscmd=(char *) malloc(1024*sizeof(char));
char *cmd1=(char *) malloc(1024*sizeof(char));
char *cmd=(char *) malloc(1024*sizeof(char));
char *cmdf=(char *) malloc(1024*sizeof(char));
char *arg1=(char *) malloc(1024*sizeof(char));
char *allarg=(char *) malloc(1024*sizeof(char));
char *arg2=(char *) malloc(1024*sizeof(char));
char *arg3=(char *) malloc(1024*sizeof(char));
while (1) {
/* Ektypwse to command prompt */
printf("$ ");
fflush(stdout);
fgets(line, 1024, stdin); //Reads the command.
for(i=0;i<1024;i++){
if(line[i]=='\n') //Deletes the "Enter" from the end of the string.
{
line[i]='\0'; //Replace "Enter" with \0.
}
if(line[i] == 'e' && line[i+1] == 'x' && line[i+2] == 'i' && line[i+3] == 't' ) {
exit(1);
}
}
seccmd = strchr(line, '|');
acc = 0;
for(i=0;i<1024;i++){
if(line[i]=='|'){
acc = i;
t=t+1;
} //Finds the second space.
}
/*FIRST COMMAND AND ARGUMENT*/
if(acc != 0 ){
//printf("OKIF\n");
for(j=0;j<acc;j++){
//printf("OKFOR\n");
frscmd[j]= line[j];
}
//printf("FIRST COMMAND %s\n", frscmd);
}
/*FIRST ARG*/
frsarg = strchr(frscmd, sp);
if(frsarg != NULL){
while(isspace(*frsarg)) ++frsarg;
}
for (i=0;i<1024;i++){
if (frsarg[i] == ' '){
frsarg[i] = '\0';
}
}
/*FIRST COMMAND*/
acc = 0;
for(i=0;i<1024;i++){
if(frscmd[i]==' '){
acc = i;
break;
}
}
if(acc != 0 ){
//printf("OKIF\n");
for(j=0;j<acc;j++){
//printf("OKFOR\n");
firstcmd[j]= frscmd[j];
}
}
if(firstcmd != NULL){
while(isspace(*firstcmd)) ++firstcmd;
}
printf("FIRST COMMAND TEST %s TEST\n", firstcmd);
printf("FIRST ARGUMENT TEST %s TEST\n", frsarg);
// firstcmd == "ls" ,frsarg == "-l"
/*SECOND COMMAND AND ARGUMENTS */
//seccmd = " | ws -l
//SECOND COMMAND WITHOUT "|" secondcmd = _wc_-l
secondcmd = strchr(seccmd, sp);
if(secondcmd != NULL){
while(isspace(*secondcmd)) ++secondcmd;
}
//SECCOND COMMAND scmd
acc = 0;
for(i=0;i<1024;i++){
if(secondcmd[i]==' '){
acc = i+1;
}
}
if(acc != 0 ){
for(j=0;j<acc;j++){
scmd[j]= secondcmd[j];
}
}
for (i=0;i<1024;i++){
if (scmd[i] == ' '){
scmd[i] = '\0';
}
}
printf("SECOND COMMAND TEST %s TEST\n", scmd);
//SECOND ARGUMENT secarg
secarg = strchr(secondcmd, sp);
if(secarg != NULL){
while(isspace(*secarg)) ++secarg;
}
printf("SECOND ARGUMENT TEST %s TEST\n", secarg);
//FIRST COMMAND = firstcmd____FIRST ARGUMENT = frsarg_____SECOND COMMAND = scmd_____SECOND ARGUMENT = secarg
if (!fork()) {
close(1); /* close normal stdout */
dup(pfds[1]); /* make stdout same as pfds[1] */
close(pfds[0]); /* we don't need this */
execlp(firstcmd, firstcmd, frsarg,(char*) NULL);
} else {
close(0); /* close normal stdin */
dup(pfds[0]); /* make stdin same as pfds[0] */
close(pfds[1]); /* we don't need this */
execlp(scmd, scmd, secarg,(char*) NULL);
}
return 0;
}
}
Well, this is a very long and complex piece of code, and the logic seems
rather ad hoc. It would take me way too long to dissect the whole
thing.
I do observe that you fork() only once, and each branch then calls
execlp() to run one of the two processes in your pipeline. That leaves
no process continuing to run the shell. So you really need to fork()
twice.
Let's say that the original process is A. After the first call to
fork() we have original process A and child A1. A then calls
wait() to pause until A1 terminates. A1 calls fork() again and
runs the pipelined commands.
Or something like that. Looking at my code bank, I see the last time I
experimented with this stuff was in 2000, and I wasn't doing two
subprocesses as you are. But this should be a step in the right
direction, anyway.
#!/bin/bash
for i in {10..11}
do
./duffing -a 1 -b -1 -u 0.25 -w -1 -A 0.4 -t $i | ./stroboscopic > $i.data
done
The $i doesn't seem to work in the program parameter line but I get the data files. This is the error
error converting i to a double for max-time:
leftover characters: i
Bad input data
error converting i to a double for max-time:
leftover characters: i
Bad input data
This is where I parse arguments in duffing program :
void parse_args(int argc, char **argv, state_t *state, system_t *system,
simulation_t *simulation, int *read_initial, int *print_final)
{
int ch;
duffing_state_t *duffing = (duffing_state_t *)system->dx_dt_state;
double dtemp;
size_t i;
while (1) {
ch = getopt_long(argc, argv, short_options, long_options, NULL);
if (ch == -1)
break;
switch(ch) {
case 'd':
simulation->dt = safe_strtod(optarg, "time-step");
break;
case 't':
simulation->t_max = safe_strtod(optarg, "max-time");
break;
case 'T':
duffing->T = safe_strtod(optarg, "transient-time");
break;
case 'x':
state->x[0] = safe_strtod(optarg, "x0");
break;
case 'v':
state->x[1] = safe_strtod(optarg, "v0");
break;
case 'm':
system->m = safe_strtod(optarg, "mass");
break;
case 'a':
duffing->a = safe_strtod(optarg, "alpha");
break;
case 'b':
duffing->b = safe_strtod(optarg, "beta");
break;
case 'u':
duffing->u = safe_strtod(optarg, "mu");
break;
case 'w':
duffing->w = safe_strtod(optarg, "omega");
break;
case 'A':
duffing->A = safe_strtod(optarg, "amplitude");
break;
case 'E':
simulation->step_fn = &euler_step;
break;
case 'M':
simulation->step_fn = &midpoint_step;
break;
case 'R':
simulation->step_fn = &rk4_step;
break;
case 'i':
*read_initial = 1;
break;
case 'f':
*print_final = 1;
break;
case '?':
exit(EXIT_FAILURE);
default:
fprintf(stderr, "?? getopt returned character code 0%o ??\n", ch);
}
}
/* convert input from periods to seconds */
simulation->t_max *= 2*M_PI / duffing->w;
duffing->T *= 2*M_PI / duffing->w;
return;
}
I have ran the program straight from the terminal with the -t 10 so I'm pretty confused why the program is refusing to accept the input from the script.
I'm new to scripting, but I have a lot of experience programming in languages such as C# and Java.
I have a file that contains binary data. I want to write a Bash script that reads the year, month, and day contained in that file so I can sort the associated MOD files into folders according to the date they were recorded. I'm having trouble finding a way to read binary data and parsing it in a bash script. Is there any way to do this?
You can use od (plus head and awk for a little post-processing) for this. To get the year:
year=$(od -t x2 --skip-bytes=6 --read-bytes=2 file.moi | head -1 | awk '{print $2}')
For the month:
month=$(od -t x1 --skip-bytes=8 --read-bytes=1 file.moi | head -1 | awk '{print $2}')
And the day:
day=$(od -t x1 --skip-bytes=9 --read-bytes=1 file.moi | head -1 | awk '{print $2}')
I would recommend using python for this.
However, if you insist on bash, i would try using either sed in binary mode (never tried it) or using dd for extracting specific bytes and then convert them.
If this is not too hardcore for you I suggest compiling the following C-language program:
#include <stdio.h>
#include <inttypes.h>
typedef union {
char array[sizeof(int32_t)];
int32_t val;
} int32_u;
typedef union {
char array[sizeof(uint32_t)];
uint32_t val;
} uint32_u;
typedef union {
char array[sizeof(uint64_t)];
uint64_t val;
} uint64_u;
typedef union {
char array[sizeof(int64_t)];
int64_t val;
} int64_u;
int swap(char* mem, int size) {
if (size & 1 != 0)
return -1;
int i;
for (i = 0; i < size / 2; i++) {
char tmp = mem[i];
mem[i] = mem[size - i - 1];
mem[size - i - 1] = tmp;
}
return 0;
}
int sys_big_endian() {
int x = 1;
return !(*(char*)&x);
}
int main(int argc, char** argv) {
char* file_name = NULL;
int offset = 0;
char* type = "int32";
int big_endian = 0;
int i;
for(i = 1; i < argc; i++) {
if(!strncmp("-o", argv[i], 2)) {
++i;
sscanf(argv[i], "%d", &offset);
} else if(!strncmp("-t", argv[i], 2)) {
++i;
type = argv[i];
} else if(!strncmp("-e", argv[i], 2)) {
++i;
big_endian = !strncmp("big", argv[i], 3);
} else {
file_name = argv[i];
break;
}
}
if (i < argc - 1) {
fprintf(stderr, "Ignoring extra arguments: ");
++i;
for (; i < argc; i++) {
fprintf(stderr, "%s ", argv[i]);
}
fprintf(stderr, "\n");
}
if (file_name == NULL) {
fprintf(stderr, "Syntax: readint [-o offset] [-t type] [-e endian] <filename>\n"
"Where:\n"
" type 'uint32', 'uint64', 'int32' (default), 'int64'.\n"
" endian 'big' or 'little' (default).\n"
" offset offset in a file from where the read will happen, default is 0.\n"
);
return -1;
}
FILE* fp = fopen(file_name, "rb");
if (fp == NULL) {
fprintf(stderr, "Could not open the file: %s\n", file_name);
return -1;
}
fseek(fp, offset, SEEK_SET);
if (!strncmp("uint32", type, 6)) {
uint32_u u;
fread(u.array, sizeof(u.array), 1, fp);
if (big_endian ^ sys_big_endian())
swap(u.array, sizeof(u.array));
printf("%u\n", u.val);
} else if (!strncmp("int32", type, 5)) {
int32_u u;
fread(u.array, sizeof(u.array), 1, fp);
if (big_endian ^ sys_big_endian())
swap(u.array, sizeof(u.array));
printf("%d\n", u.val);
} else if (!strncmp("uint64", type, 6)) {
uint64_u u;
fread(u.array, sizeof(u.array), 1, fp);
if (big_endian ^ sys_big_endian())
swap(u.array, sizeof(u.array));
printf("%"PRIu64"\n", u.val);
} else if (!strncmp("int64", type, 5)) {
int64_u u;
fread(u.array, sizeof(u.array), 1, fp);
if (big_endian ^ sys_big_endian())
swap(u.array, sizeof(u.array));
printf("%"PRId64"\n", u.val);
} else {
printf("Unknown type: %s\n", type);
}
fclose(fp);
return 0;
}
Then do this:
gcc -o readint readint.c
sudo mv readint /usr/local/bin
Now you have a handy tool called 'readint' with the following syntax:
readint [-o offset] [-t int32|uint32|int64|uint64 ] [-e little|big ] <filename>
you can search the net for modules to interpret MOI files (either Perl or Python). Otherwise, i don't really think you can get the date just like that from the binary file because if you look inside, its really "garbage" since its binary. Although you may also give the strings command a try to see if there are legible strings that match the date