I created a little mini shell and it let's the user enter a command like 'ls' and it will list the contents of the directory like it's supposed to using execv() in my code, but that doesn't seem to work for when the user enters something like 'set name="bob"'. I've been looking all over the place for what I should use in my code to execute a set command when the user enters it and the best I can find is system(), but that still isn't working for me. Any ideas?
set is a shell-builtin command, not an external command (indeed it needs to be to have the intended effect, which is to modify a shell variable within the shell process itself).
This means that you need to look for and handle set within your shell itself, by adding the named variable to some internal data structure that tracks shell variables (or updating it if it already exists there).
Since you're doing a fork-and-exec or a system(), the command is really being run in a separate process. What happens in that process (like setting an environment variable) does not affect the parent's environment. (A separate issue is that set doesn't actually create an environment variable. You'd need export in [ba]sh or setenv in [t]csh to do that.)
So you need to code your mini-shell to handle the set command explicitly, rather than passing it off to another program.
You might want to look at setenv(3) and getenv(3). These are functions for changing and reading environment variables from within a C program.
Related
So I'm not exactly sure if this is possible, but I would like to use unix's alias command for creating aliases of commands I have created inside of my C program.
So far the only idea I have had to try is system(alias ='someCommand');
This resulted in nothing happening
Is this even possible? Or do I have to essentially create my own alias function for my c program (which is a simple shell program)
Thanks, I'm new to this and would appreciate any insight!
Aliases are meant as shortcuts that you create to reduce your typing when working inside the shell. When you execute a program that you created by compiling your C source code, the shell forks and execs the program. Any changes that you intend to make to the shell happen inside that execed code. As soon as the program is terminated, your changes disappear with it. Hence, what you observe: "Nothing happens".
I'm working on an old C software. There is one ksh script which executes a C program, which then creates some other processes and ends. These processes remain alive.
I'm trying to set an environment variable inside my ksh script, so that it could be accessible in the newly created processes that are still alive.
I have tried this way :
#!/bin/ksh
VARIABLE=value
export VARIABLE
my_c_program
But that doesn't work... I have tried to :
change my ksh script to bash
create a wrapper script that creates and exports the variable and then executes the original ksh script (which just executes the C program)
sourcing my ksh script (or my wrapper script when trying with 2.) instead of executing
it
But nothing from that worked.
The only thing that works for now is when I explicitly, by hand, execute the command :
export VARIABLE
In the current bash terminal.
Why? Isn't it possible to do the export inside a script instead of doing it manually?
Everything is ok actually...
The fact is that the process I thought was the child of the C program executed in my ksh script was the child of another process executed before. The C program was just sending a message via shared memory to tell the other program to execute its child.
So indeed the environment variable never went from my C program to the other's child. The only time when I had that variable set in the child is when I executed the other program (the one which is the real parent of the child) in a shell where the variable was exported.
The code above looks correct and it should work. Another way to do it is:
VARIABLE=value my_c_program
which exports the variable just for the program. Afterwards, the variable will be set but other external processes don't get a copy.
So why doesn't your script work? It's hard to tell but here are some tips to debug the issue:
Use #!/bin/ksh -x to enable debug output. Save the output in a file and then grep VARIABLE to make see what happens with it.
Check for typos.
Another shell script is like an external process. So create a script
#!/bin/ksh
echo $VARIABLE
and call it instead of my_c_program just to make sure passing the variable on works.
Maybe the C does something unexpected. Use a debugger to make sure it does what you expect.
I've written an application in C that is supposed to be reading environmental variables and handling those changes appropriately. When the application starts, I've set it up to go ahead and initialize the variable (to prevent any null pointers from returning) via setenv("MYVARIABLE", "TEST", 1).
This application loops often and, during those loops, one of its jobs is to check that global variable via getenv("MYVARIABLE").
The plan then was to have either a shell script or a python script change these environmental variables. The C application is full screen, so I have no way of testing this process without another terminal entry. In my other terminal (c2) I run commands such as:
MYVARIABLE="My New Value"
or
export MYVARIABLE="My New Value"
My application doesn't seem to catch the environmental update, though. Instead it continues to insist that MYVARIABLE is "test," and not "My New Value." I'm not sure why these two environments are separate, but I need them to work together. Does anyone know what I'm doing wrong?
My system is running Archlinux for anyone who is interested
The problem you're facing right now is that you've only set your variable in the local shell session's scope. EX:
(Assuming bash) When you set a variable such as:
MYVARIABLE="My New Value"
it only effects the current shell, when you set it as:
export MYVARIABLE="My New Value"
it effects the current shell and all processes started from the current shell.
If you set it in your .bashrc file it will set it permanently for all future sessions, but you'll need to source that file for it to work in your current session.
The best solution is to fork off a process. For example if your program is called a.out you can execute:
> ./a.out &
This will allow you to continue to work in the shell session while the program is running, then you can set variables in that same session.
The only other option I've ever seen is to force your shell session to "auto" source things as they come in:
1) In your first session enter:
trap 'source ~/.bashrc' DEBUG
2) Then start your program in the same session:
./a.out
3) In a second window edit your .bashrc file to add the new env var
4) in the second window source the new version of the file:
source ~/.bashrc
Now the first window running your program has the new var set to its session. I've used that before and I know it works, but I've never tried it on an applications that was already spawned.. but I suspect it should work for you.
Your process environment is not dynamically changeable!!!
Remember this main() prototype...
int main (int argc, char *argv[], char *envp[])
{
char *path;
/*
Searches in this process envp[] only,
There is no way it can access changes happening in Shell command prompt...
User shell does not communicate with this process, if not piped.
This will always return PATH, that was set at the time of starting.
*/
while (1)
{
path = getenv("PATH");
sleep (5);
printf("PATH = %s\n", path);
free(path);
};
}
Your understanding of getenv() library function is WRONG. To achieve your expectation, You need to use any form of IPC.
setenv() works with calling process own environment. That will be passed on to it own child process through fork(), exec() syscalls. This will will not do anything in the parent process, your shell.
I am wanting to make a terminal app that stores information about files/directories. I want a way to keep the information if the file is moved or renamed.
What I thought I could do is have a function execute before any command is run. I found this:
http://www.twistedmatrix.com/users/glyph/preexec.bash.txt
But I was wondering if this would be a good way to go about it. Or should I do something else?
I would like to call that function from a C program whenever mv is entered I suppose.
If what you're trying to do is attach some sort of metadata to files, there's a much better supported way to do that -- extended attributes.
Another solution might be to use the file's inode number as an index into a database you maintain yourself.
Can you alias the mv command? in .profile or .bashrc
alias mv=/usr/bin/local/mymv
where mymv is a compiled executable that runs your C code function and calls /usr/bin/mv.
precmd and preeexec add some overhead to every bash script that gets run, even if the script never calls mv. The downside to alias is that it requires new code in /usr/local and if scripts or users employ /usr/bin/mv instead of mv it will not do what you want. Generally doing something like this often means there is a better way to handle the problem with some kind of service (daemon) or driver. Plus, what happens if your C code cannot correctly handle interesting input like
mv somefille /dev/null
If you want to run command each time after some command was executed in the terminal, just put the following in ~/.bashrc:
PROMPT_COMMAND="your_command;$PROMPT_COMMAND"
If you want your command to be executed each time before mv is executing, put the following in ~/.bashrc:
alias mv="your_script"
Make sure that your script will execute real mv if needed.
You can use inotify library to track filesystem changes. It's good solution, but once user remove file, it's already gone.
You might be able to make use of the DEBUG trap in Bash.
From man bash:
If a sigspec is DEBUG, the command arg is executed before every
simple command, for command, case command, select command, every
arithmetic for command, and before the first command executes in
a shell function
I found this article when I was forced to work in tcsh and wanted to ensure a specific environemtn variable was present when the user ran a program from a certain folder (without setting that variable globally)
tcsh can do this.
tcsh has special alias, one of which is precmd
This can be used to run a script just before the shell prompt is printed.
e.g. I used set precmd 'bash $HOME/.local/bin/on_cd.sh'
This might be one of the very few useful features in csh.
It is a shame but I don't think the same or similar feature is in bash or other sh derivites (ash, dash etc). Related answer.
Can I set LD_LIBRARY_PATH for an individual application?
I am looking into system call failure, so is there any way I can set set the correct path using the LD_LIBRARY_PATH setting?
Simplest way would be to create a shell script.
Have the shell script export your new LD_LIBRARY_PATH variable then launch your application
e.g. (where foo is your app)
#!/bin/sh
LD_LIBRARY_PATH=some_path:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH
foo
As simple as:
LD_LIBRARY_PATH=new_path:$LD_LIBRARY_PATH foo
which works in bash. I think it works in all bourne shell derivatives, but I can't guarantee it.
Of course, with this approach, you have to type the path every time. To do it repeatedly, prefer Glen's approach.
One item to be aware of: you cannot set LD_LIBRARY_PATH within a program and make it have any effect on the current program. This is because the dynamic loader (ld.so.1 or some similar name) is already loaded and has read and processed the environment variable before any of your code is run. You can set it in the current process's environment, and that value will then affect any child processes, and you could use one of the exec() family of functions to run a program with the environment set. In an extreme case, you could re-execute the current program - but that is extreme!