C 简单linux shell中的环境变量
我将用C语言为我的项目编写一个简单的shell,它可以实现环境变量。我查阅了如何使用getenv、setenv、putenv。到目前为止,我已经尝试使用getenv来显示shell变量…好吧。。。取得了一些成功。但我觉得我的推理有缺陷。我有一个C 简单linux shell中的环境变量,c,linux,shell,environment-variables,getenv,C,Linux,Shell,Environment Variables,Getenv,我将用C语言为我的项目编写一个简单的shell,它可以实现环境变量。我查阅了如何使用getenv、setenv、putenv。到目前为止,我已经尝试使用getenv来显示shell变量…好吧。。。取得了一些成功。但我觉得我的推理有缺陷。我有一个char**argv,其中包含来自用户输入的解析输入。我现在检查argv是否以命令“echo”开头,然后检查以下输入是否以$符号开头。这是我的密码: int executeVariables(char** arguments){ int i = 0
char**argv
,其中包含来自用户输入的解析输入。我现在检查argv
是否以命令“echo”开头,然后检查以下输入是否以$
符号开头。这是我的密码:
int executeVariables(char** arguments){
int i = 0;
if(strcmp(arguments[i], "echo") == 0){
char *variable;
for(i = 1; arguments[i] != NULL; i++){
char *str = arguments[i];
if( *(str + 0) == '$'){
variable = getenv(str + 1);
}else{
variable = getenv(str);
}
if(!variable){
//puts("not a variable");
printf("%s ", arguments[i]);
}else{
//puts("a variable");
printf("%s ", variable);
}
}
printf("\n");
exit(0);
}
return 1;
}
我认为普通的linux shell会找到$
符号,它会在调用echo命令之前展开变量。我的shell没有遵循这个原则,它在echo命令本身内部扩展变量。你知道我该怎么做吗?谢谢
编辑:
我遇到的一个问题是:echo$HOME
和echo HOME
给了我相同的结果,但结果是错误的
编辑:
经过各种测试,一切正常。但要真正测试它,我需要创建一个局部变量,然后
echo
这个值。我使用putenv
函数尝试了它,但它没有创建局部变量
i = 0;
char** temp = malloc(sizeof (*temp));
if(strstr(userInput, "=") != NULL){
//puts("we got equals");
puts(userInput);
if(putenv(userInput) == 0){
printf("doing putenv(%s)\n", userInput);
exit(0);
}
else{
puts("couldnt putenv");
exit(1);
}
}
userInput:
char*userInput
是使用fgets()
从命令行获取的输入。是的,普通shell在解析命令行期间会展开变量。所以您需要在函数中替换变量,该函数生成“包含来自用户输入的解析输入”的数组。在这种情况下,echo
(和其他命令)的代码将短得多。您特别要求代码对字符串执行getenv(),即使找不到$。这就是为什么它将显示$HOME或HOME。只需删除找不到美元符号的else情况,并确保在声明时将变量初始化为NULL,然后将其放入循环中
大概是这样的:
// First, perform replacements
int executeVariables(char** arguments){
int i = 0;
for(i = 0; arguments[i] != NULL; i++){
char *str = arguments[i];
if(*str == '$'){
// make sure the result isn't NULL, though I'm not sure a real shell does
char *tmp = getenv(str + 1);
if (tmp != NULL) {
arguments[i] = getenv(str + 1); // save off the argument
}
}
}
// Then actually execute the function. This would be like bash's echo builtin
if (strcmp(arguments[0], "echo") == 0) {
int i;
for (i = 1; arguments[i] != NULL; i++) {
printf("%s ", arguments[i]);
}
printf("\n");
}
// Other functions could go here
return 1;
}
编辑:就您的方法而言,为什么要专门检查echo?为什么不让它变得通用,并检查所有参数,包括第一个参数?实际上,您可能希望替换所有潜在的环境变量,因此,如果您在某个地方有MYECHO=echo,那么下面的方法就可以了。为了使它更通用,您需要有这个函数,它将根据扩展的变量执行这些内容。你可以把它做得很好,并且有单独的函数,但是为了适应这里的所有功能,我已经相应地更新了上面的代码,尽管我还没有测试过它。;)
Edit:话虽如此,werewindle之前关于执行此操作的评论确实适用——替换参数,如此处所示,然后使用更新的参数数组让单独的函数执行它需要执行的任何操作。:)
Edit:对于putenv()情况,您需要以下结构。这样,它将为shell以及在shell中运行的任何其他进程设置它
void do_args_env(char *args[])
{
// do putenv, etc.
}
// inside main loop in shell process
while (1) { // just an example
if (check_args_syntax(args) != 0) {
// error
}
do_args_env(args);
// fork and do other stuff
}
(希望是最终版)编辑:作为一种解释,流程通常不会(可能不会?)影响其层次结构中位于其之上的流程的环境;只有相反的方向。因此,如果在子级中放置env(),则该子级的同级(即从其父级派生的其他进程)将不会得到环境更改
很高兴我能帮上忙 你有什么问题?看起来你的代码会达到你想要的效果,不是吗?@DanFego不完全是:
echo$HOME
和echo HOME
给了我相同的结果,但结果是错误的。putenv()失败了吗,还是返回0?作为记录,整个问题可能已经被拆分了,但既然我们还在这里,我将编辑我的答案等等,putenv()不应该接受userInput,而不是*userInput吗?很抱歉,我没有完全理解您的第二句话。当您解析用户输入(如“echo my home at$home”)时,必须用实际变量值替换$home。因此,在调用executeVariables
期间,参数中的将是要处理的实际数据(即“echo”、“my”、“home”、“at”、“root”)。所有其他shell都是这样工作的。对不起,我想,您问过如何更好地替换环境变量。要修复代码,只需替换variable=getenv(str)代码>带有变量=NULL
。好的,谢谢。解决了这个问题。如果我想更好地替换环境变量呢?:)那么您应该在前面替换它们:)。或者,您很快就会发现,在处理任何shell命令期间,您都有相同的代码来替换环境变量。另外,不要忘记,变量还有其他语法,比如${MYVAR}。我想创建一个特殊函数subs_env(char*str)
,它将在解析用户输入的早期步骤中用str
中的值替换所有可能的变量。谢谢您的帮助。它解决了这个问题。我不知道为什么我甚至保留了else
条件。不管怎样,你认为我的推理正确吗?我的意思是我没有遵循正常的外壳行为。那是我的问题。我该怎么做呢?我想让它变得通用。删除第一个if
条件,然后搜索每个参数是否包含一个美元符号,然后用正确的值替换argv
,然后使用execvp(*argv,argv)
do?更新了代码,但werewindle下面的注释为您指出了正确的方向。使用arguments数组,执行替换作为自己的操作,然后执行其余操作。谢谢。让我试试。我会用新的代码更新我的问题。经过各种测试,一切都很好。但要真正测试它,我需要创建一个局部变量。我使用putenv
函数尝试了它,但它没有创建局部变量。请检查我编辑的问题。
void do_args_env(char *args[])
{
// do putenv, etc.
}
// inside main loop in shell process
while (1) { // just an example
if (check_args_syntax(args) != 0) {
// error
}
do_args_env(args);
// fork and do other stuff
}