The syntax is not like "regular" shells like sh, bash and csh. It is more of a pain to use, but easier to write!
BTW, your shell does not have to implement these. You may want to, to help you with debugging, but I won't test them. Here are some examples:
UNIX> bin/jshell r # The 'r' on command line means that it will
READY # print "READY" when it's ready to receive a command
cat f1.txt
END # You need an "END" line to make it execute the command
Andrew Sundry
Brandon Aperiodic
Gianna Coralberry
Sydney Roundoff
Brandon Canvas
Julia Suffocate
Amelia Chantey
Isaiah Aidan Plait
Lucy Clamp
Arianna Infant
READY
# I'm putting an extra line after the READY's to make it easier to read.
< f1.txt # Here, we redirect standard input from f1.txt
head -n 2
> f2.txt # And standard output to f2.txt
END
READY
cat f2.txt # Here's f2.txt
END
Andrew Sundry
Brandon Aperiodic
READY
> f2.txt # It doesn't matter what order you specify the
< f1.txt # redirections with respect to the commands.
head -n 2
END
READY
cat f2.txt
END
Andrew Sundry
Brandon Aperiodic
READY
head -n 2 f1.txt # Test appending to a file
>> f2.txt
END
READY
cat f2.txt
END
Andrew Sundry
Brandon Aperiodic
Andrew Sundry
Brandon Aperiodic
READY
cat -n # Here's where we pipe together three commands
sed s/[a-z]/x/g
tail -n 2
< f1.txt
END
9 Lxxx Cxxxx
10 Axxxxxx Ixxxxx
READY
cat sleep_fred.c # sleep_fred.c sleeps 10 seconds and then
END # prints Fred on standard output.
#include
#include
#include
int main()
{
sleep(10);
printf("Fred\n");
exit(0);
}
READY
gcc sleep_fred.c # We compile it and run it
END
READY
a.out
END
Fred # You have to wait 10 seconds for it to print Fred.
READY # After 10 seconds, it prints Fred and you get the READY prompt.
a.out # Now I run it, but speify NOWAIT
NOWAIT
END
READY # I get the prompt back instantly, with no Fred.
cat f2.txt # I call this command in under 10 seconds
END
Andrew Sundry
Brandon Aperiodic
READY
Fred # And finally Fred appears.
a.out # I call a.out > f2.txt, but don't wait.
> f2.txt
NOWAIT
END
READY
cat f2.txt # Within 10 seconds, f2.txt has been opened and
END # truncated, but nothing written yet.
READY
cat f2.txt # (Wait 10 seconds): After 10 seconds, f2.txt contains "Fred".
END
Fred
READY
<CNTL-D>
UNIX>
When you call my jshell and include 'p' in the first argument, it will print information
about the command:
UNIX> bin/jshell rp
READY
cat f1.txt
END
Stdin: None # After each command, you can see my internal data structure.
Stdout: None (Append=0)
N_Commands: 1
Wait: 1
0: argc: 2 argv: cat f1.txt
Andrew Sundry
Brandon Aperiodic
Gianna Coralberry
Sydney Roundoff
Brandon Canvas
Julia Suffocate
Amelia Chantey
Isaiah Aidan Plait
Lucy Clamp
Arianna Infant
READY
cat -n
sed s/[a-z]/x/g
tail -n 2
< f1.txt
> f2.txt
END
Stdin: f1.txt
Stdout: f2.txt (Append=0)
N_Commands: 3
Wait: 1
0: argc: 2 argv: cat -n
1: argc: 2 argv: sed s/[a-z]/x/g
2: argc: 3 argv: tail -n 2
READY
cat f2.txt
END
Stdin: None
Stdout: None (Append=0)
N_Commands: 1
Wait: 1
0: argc: 2 argv: cat f2.txt
9 Lxxx Cxxxx
10 Axxxxxx Ixxxxx
READY
head -n 1 f1.txt
>> f2.txt
END
Stdin: None
Stdout: f2.txt (Append=1)
N_Commands: 1
Wait: 1
0: argc: 4 argv: head -n 1 f1.txt
READY
cat f2.txt
END
Stdin: None
Stdout: None (Append=0)
N_Commands: 1
Wait: 1
0: argc: 2 argv: cat f2.txt
9 Lxxx Cxxxx
10 Axxxxxx Ixxxxx
Andrew Sundry
READY
NOWAIT
a.out
END
Stdin: None
Stdout: None (Append=0)
N_Commands: 1
Wait: 0
0: argc: 1 argv: a.out
READY
Fred # This comes 10 seconds later
<CNTL-D>
UNIX>
cat f1 > /dev/null NOWAIT END vi lab3.c ENDYou are going to call wait() to wait for the vi command to terminate, but it will return with the status of the zombie process from the cat call. This is all fine -- you just need to be aware that these things may happen, and that you may have to call wait() again to wait for vi to complete.
Also, when a command is done, and the shell prints out its prompt, then it should only have three files open -- 0, 1, and 2. Otherwise, you have forgotten to close a file descriptor or two and have a bug in your code. Check for this. My jshell never uses a file descriptor higher than 5.
To help you out, I have made videos to explain gradescripts 6, 21 and 61. They are here:
typedef struct {
char *stdin; /* Filename from which to redirect stdin. NULL if empty.*/
char *stdout; /* Filename to which to redirect stdout. NULL if empty.*/
int append_stdout; /* Boolean for appending.*/
int wait; /* Boolean for whether I should wait.*/
int n_commands; /* The number of commands that I have to execute*/
int *argcs; /* argcs[i] is argc for the i-th command*/
char ***argvs; /* argcv[i] is the argv array for the i-th command*/
Dllist comlist; /* I use this to incrementally read the commands.*/
} Command;
|
A little commentary -- before I read END, I put commands into comlist, and keep track of the number of commands with n_commands. I build the argv array when I read the command, and that's what I put onto the comlist.
When I read END, I create argcs and argvs from comlist, and then delete comlist. Since I'm storing the actual argv arrays in comlist, this is a very simply process of calculating argc, and then copying the pointer to the argv array.
I have a procedure free_command() that frees everything in the data structure at the end of every command. I use this to handle errors while reading.