Programmer 400 Programmer 400 - 5 months ago 24
Bash Question

shebang for custom shell?

I'm writing a custom shell and I want it to execute a script:

if [ type less > /dev/null ];then PAGER=less; fi
echo $PAGER
printenv|grep $1|$PAGER


It works if I run it from the bash and with my custom shell:

$ ./shell -f ../checkenv.sh GNOME
[13607]
[13606]
GNOME_KEYRING_CONTROL=
GNOME_KEYRING_PID=
GNOME_DESKTOP_SESSION_ID=this-is-deprecated
INSTANCE=GNOME
XDG_CURRENT_DESKTOP=GNOME
(END)


But if I start my shell and then try and run the script, I get an error message.

$ ./shell
'PATH' is set to /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/go/bin.
$ ../checkenv.sh GNOME
14786: executing ../checkenv.sh
../checkenv.sh: 2: [: type: unexpected operator

14786: executed
$


This seems to be because I don't have a shebang, but I don't know how to use a shebang for a custom shell. Should I install my custom shell in
/usr/bin/
or make some other arrangement?

My main function and my readline function are:

int main(int argc, char *argv[]) {
bool donotrun = false;
struct sigaction new_action, old_action;
hashtable_t *hashtable = ht_create(65536);
/* Set up the structure to specify the new action. */
new_action.sa_handler = termination_handler;
sigemptyset(&new_action.sa_mask);
new_action.sa_flags = 0;

sigaction(SIGINT, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN)
sigaction(SIGINT, &new_action, NULL);
sigaction(SIGHUP, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN)
sigaction(SIGHUP, &new_action, NULL);
sigaction(SIGTERM, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN)
sigaction(SIGTERM, &new_action, NULL);

bool background = false;
int index = 0;
int i;
char *cvalue = NULL;
const char *commandFile = NULL;

while (1) {
index = 0;
i = getopt_long(argc, argv, "pc:fvh",
options, &index);
if (i == -1)
break;
switch (i) {
case 'p': {
exit(EXIT_SUCCESS);
}
case 'v': {
printf("sh OpenShell version 0.1(a)\n");
printf("Version: %s\n", VERSION);

// printf ("%s / %s / %s / %s\n",
// program_name, version,
// build_date, build_git_sha);


exit(EXIT_SUCCESS);

}
case 'h': {
usage();
exit(EXIT_SUCCESS);

}
case 'c': {
cvalue = optarg;
command(cvalue, hashtable, background);
exit(EXIT_SUCCESS);
}

case 'f': {
/*
* Execute commands from file.
* This is used for osh script files.
* The quiet flag is also set.
*/
//if ((argc != 1) || commandFile)
//usage();
//quietFlag = TRUE;
printf("case f\n");
//commandFile = *argv++;

argc--;
*argv++;
*argv++;
readFile(*argv++, argc, argv, hashtable, background);
//free(line);
exit(0);

//break;
}

case '?':
if (optopt == 'c')
fprintf(stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf(stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf(stderr,
"Unknown option character `\\x%x'.\n",
optopt);
default: {
return 1;
}
}
}
getPath();
char *copy = "";

for (; ;) {
bool scanning = true;
while (scanning) {
char *line = NULL;
line = readline("$ ");
if (line == NULL) {
/* No more lines, so exit the loop. */
break;
}
if (line)
copy = strdup(line);

if (line && !strstr(line, "for") && !strstr(line, "==") && !strstr(line, "if") && strstr(line, "=")) {
donotrun = true;
char str[128];
char *ptr;
strcpy(str, line);
strtok_r (str, "=", &ptr);
ht_set(hashtable, str, ptr);
}

if (!scanning)
break;

if (commandFile!=NULL || !isatty(fileno(stdin))) {
*argv++;
readFile(*argv++, argc, argv, hashtable, background);
free(line);
exit(0);
}
else {
if (!donotrun) {
line = strrep(line, " | ", "|");
line = strrep(line, " |", "|");
background = testFn2(line);
if (background)
line[strlen(line) - 1] = '\0';
command(line, hashtable, background);
}
donotrun = false;
add_history(copy);

}
free(copy);
}
}
// ParseFree(pParser, free);FIXME: where should this go?
return 0;
}


/*
* Read commands from the specified file.
* A null name pointer indicates to read from stdin.
*/
static int readFile(const char *name, int argc, char ** argv, hashtable_t *hashtable, bool background) {
FILE *fp;
int cc;
bool ttyFlag;
char buf[CMD_LEN];
int r = 0;

if (sourceCount >= MAX_SOURCE) {
fprintf(stderr, "Too many source files\n");

return 1;
}

fp = stdin;
printf("name %s\n", name);

if (name) {
fp = fopen(name, "r");

if (fp == NULL) {
perror(name);

return 1;
}
}

sourcefiles[sourceCount++] = fp;

ttyFlag = isatty(fileno(fp));
int i = 0;
while (true) {
if (ttyFlag)
showPrompt();

if (intFlag && !ttyFlag && (fp != stdin)) {
fclose(fp);
sourceCount--;

return 1;
}
if (fgets(buf, CMD_LEN - 1, fp) == NULL) {
if (ferror(fp) && (errno == EINTR)) {
clearerr(fp);

continue;
}

break;
}

cc = strlen(buf);
if (buf[cc - 1] == '\n')
cc--;

while ((cc > 0) && isBlank(buf[cc - 1]))
cc--;

buf[cc] = '\0';
//printf("buf %s\n", argv[0]);
strreplace(buf, "$1", argv[0]);

//printf("arg %s\n", ++argv);

if (strstr(buf, "=")) {
char str[128];
char *ptr;
strcpy(str, buf);
strtok_r (str, "=", &ptr);
ht_set(hashtable, str, ptr);
}

//printf("the command is %s\n", buf);
r = command(buf, hashtable, background);
i++;
}

if (ferror(fp)) {
perror("Reading command line");

if (fp == stdin)
exit(1);
}

clearerr(fp);

if (fp != stdin)
fclose(fp);

sourceCount--;

return r;
}

Answer

You might simply remove the square brackets in your script test:

if type less > /dev/null ;then PAGER=less; fi
echo $PAGER
printenv|grep $1|$PAGER