如何让这个程序的输出,全部重定向到一个文件?要改哪块?
//
// main.cpp
// testofcmd
//
// Created by mac mac on 13-6-5.
// Copyright (c) 2013年 __MyCompanyName__. All rights reserved.
//
/********************************************************
* @author Airead Fan <fgh1987168@gmail.com>*
* @date 2011 9月 09 20:00:47 CST*
********************************************************
*after studying C 53 days*
*after studying APUE 18 days*
********************************************************/
/*
* This program implement shell
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "shell.h"
#define DEBUG 1
#define BUFSIZE 1024
#define CMDNUMBER 100
int main()//int argc, char *argv[])
{
char arg[BUFSIZE];
ssize_t readbytes;//long型
char str_prompt[BUFSIZE + 1];
//while(1)
//{
FILE *fp = NULL;
fp = fopen("/season/out.txt","ab+");
fprintf(fp, "%s", shell_prompt(str_prompt));
fflush(fp);
//void *memset(void *s, int c, size_t n);
memset(arg, 0, sizeof(arg));
//ssize_t read(int fd, void *buf, size_t count);
//if((readbytes = read(STDIN_FILENO, arg, BUFSIZE)) < 0)
// {
//fprintf(stderr, "read failed: %s\n", strerror(errno));
//exit(1);
//}
strcat(arg,"ls -al");
if(arg[readbytes - 1] == '\n')
{ /* clear '\n' at end of arg */
arg[readbytes - 1] = '\0';
}
//if(isquit(arg) == 1)
//{ /* check quit or not */
//break;
//}
//int dealarg(char *arg);
dealarg(arg);
//}
return 0;
}
/*
* parse args
* note that: args[n] and arg shared memory!
*/
int parse_args(char *args[], char *arg)
{
char **p;
char *q;
int ch;
int count;
p = args;
q = arg;
count = 0;
while(*q != '\0'){
//int read_char(char *arg);
while((ch = read_char(q)) == ' '){ /* skip space */
q++;
}
*p++ = q++;
count++;
ch = read_char(q);
while(ch != ' ' && ch != '\0'){ /* find first space after word */
q++;
ch = read_char(q);
}
if(ch != '\0'){
*q++ = '\0';
ch = read_char(q);
}
}
return count;
}
/*
* filter string
*/
int read_char(char *str)
{
char filter[] = " \t\n";
char *p;
int flag;/* flag 1 return ' ', 0 return *str */
flag = 0;
p = filter;
while(*p != '\0')
{
if(*str == *p)
{
flag = 1;
break;
}
p++;
}
if(flag == 1)
{
return ' ';
}
else
{
return *str;
}
}
/*
* print shell prompt
*/
char *shell_prompt(char *promptbuf)
{
char tmpbuf[BUFSIZE + 1];
//void *memset(void *s, int c, size_t n);
memset(promptbuf, 0, BUFSIZE + 1);
memset(tmpbuf, 0, sizeof(tmpbuf));
//char *getcwd(char *buf, size_t size);获取当前绝对目录
if(getcwd(tmpbuf, sizeof(tmpbuf) - 1) == NULL)
{
fprintf(stderr, "%s:%d: getcwd failed: %s\n",
__FILE__, __LINE__, strerror(errno));
exit(1);
}
//int snprintf(char *str, size_t size, const char *format, ...);
snprintf(promptbuf, BUFSIZE, "%s$ ", tmpbuf);
return promptbuf;
}
/*
* if args == quit
*/
int isquit(char *arg)
{
//int strcmp(const char *s1, const char *s2);
if(strcmp(arg, "quit") == 0)
{
return 1;
}
else
{
return 0;
}
}
/*
* Receive message and deal something
*/
int dealarg(char *arg)
{
int cmdnum;
char *args[CMDNUMBER];
int argnum;
//int parse_args(char *args[], char *arg);
argnum = parse_args(args, arg);
args[argnum] = NULL;
#if DEBUG
int i;
fprintf(stdout, "argnum = %d\n", argnum);
for(i = 0; i < argnum; i++){
fprintf(stdout, "[%d]%s\n", i, args[i]);
}
#endif
//int get_cmdnum(char *cmd)
cmdnum = get_cmdnum(args[0]);
switch(cmdnum){
case SHELL_EMPTY:
break;
case SHELL_CD:
//int shell_cd(char *args[])
shell_cd(args);
break;
case SHELL_FORK:
//int shell_fork(char *args[])
shell_fork(args);
break;
default:
fprintf(stdout, "%s:%d: getcmd failed\n", __FILE__, __LINE__);
break;
}
return 0;
}
/*
* fork and called exec
*/
int shell_fork(char *args[])
{
pid_t pid[CMDNUMBER];
int status;
int fork_num;
char **p;/* point args */
char *q;/* point *args */
/* get numbers of child process*/
fork_num = 1;
p = args;
while(*p != NULL){
q = *p;
while(*q != '\0')
{
if(*q == '|')
{
fork_num++;
}
q++;
}
p++;
}
#if DEBUG
fprintf(stdout, "fork_num = %d\n", fork_num);
#endif
/* case: child process number is one */
if(fork_num < 2){
//pid_t fork(void);
if((pid[0] = fork()) < 0)
{
/* error */
perror("fork");
exit(1);
}
else if(pid[0] == 0)
{
/* child process */
//int execvp(const char *file, char *const argv[]);
if(execvp(args[0], args) < 0)
{
perror("");
exit(1);
}
exit(0);
}
}
/* parent process */
//pid_t waitpid(pid_t pid, int *status, int options);
if(fork_num < 2)
{
waitpid(pid[0], &status, 0);
}
else
{
//int mutifork(char *args[])
status = mutifork(args);
}
return status;
}
/*
* likes shell's cd
*/
int shell_cd(char *args[])
{
char buf[BUFSIZE + 1];
memset(buf, 0, BUFSIZE + 1);
if(args[1][0] != '/' && args[1][0] != '.')
{
//char *getcwd(char *buf, size_t size);
if(getcwd(buf, BUFSIZE) == NULL)
{
fprintf(stderr, "%s:%d: getcwd failed: %s\n", __FILE__,
__LINE__, strerror(errno));
return -1;
}
strncat(buf, "/", BUFSIZE - strlen(buf));
}
//char *strncat(char *dest, const char *src, size_t n);
strncat(buf, args[1], BUFSIZE - strlen(buf));
#if DEBUG
fprintf(stdout, "%s\n", buf);
#endif
//int chdir(const char *path);
if(chdir(buf) == -1){
fprintf(stderr, "%s:%d: chdir failed: %s\n", __FILE__,
__LINE__, strerror(errno));
}
return 0;
}
/*
* Change cmd to int, according to shell.h
*/
int get_cmdnum(char *cmd)
{
if(cmd == NULL) return SHELL_EMPTY;
if(strcmp(cmd, "cd") == 0) return SHELL_CD;
return SHELL_FORK;
}
int mutifork(char *args[])
{
int pipefd[CMDNUMBER][2];
pid_t pid[CMDNUMBER];
int i, j;
int count;
int status;
char **arg_child[CMDNUMBER];
char **p;
char ***q;
/* parse and split args to child arg */
count = 0;
p = args; q = arg_child;
while(*p != NULL && p != NULL){
*q++ = p;
count++;
while(*p != NULL && strcmp(*p, "|") != 0){
p++;
}
if(*p != NULL){
*p++ = NULL;
}
}
*q = NULL;
#if DEBUG/* check child args */
fprintf(stdout, "----------------------------------------\n");
fprintf(stdout, "count = %d\n", count);
q = arg_child; i = 0;
while(*q != NULL){
p = *q++;
while(*p != NULL){
fprintf(stdout, "[%d]%s\n", i, *p++);
}
i++;
}
#endif
/* fork count child process */
for(i = 0; i < count; i++)
{
/* init pipe file descriptor */
if(pipe(pipefd[i]) < 0)
{ /* FIXME: excess one */
perror("pipe");
return -1;
}
/* fork child i */
if((pid[i] = fork()) < 0)
{
fprintf(stderr, "%s:%d: fork() failed: %s\n", __FILE__,
__LINE__, strerror(errno));
return -1;
}
else if(pid[i] == 0)
{
/* child i */
//int dup2(int oldfd, int newfd);
if(i == 0){ /* the first child */
close(pipefd[i][0]); /* close curr process read */
if(dup2(pipefd[i][1], STDOUT_FILENO) < 0)
{
perror("dup2 failed");
return -1;
}
}
else if(i == count - 1)
{ /* the last child */
for(j = 0; j < i - 1; j++)
{ /* close unuse pipefd */
close(pipefd[j][1]);
close(pipefd[j][0]);
}
close(pipefd[j][1]); /* close prev process end of write */
close(pipefd[i][0]); /* close curr process end of read */
if(dup2(pipefd[j][0], STDIN_FILENO) < 0){
perror("dup2 failed");
return -1;
}
}
else
{
for(j = 0; j < i - 1; j++)
{ /* close unuse pipefd */
close(pipefd[j][1]);
close(pipefd[j][0]);
}
close(pipefd[j][1]); /* close prev process end of write */
close(pipefd[i][0]); /* close curr process end of read */
if(dup2(pipefd[j][0], STDIN_FILENO) < 0)
{
perror("dup2 failed");
return -1;
}
if(dup2(pipefd[i][1], STDOUT_FILENO) < 0)
{
perror("dup2 failed");
return -1;
}
}
//int execvp(const char *file, char *const argv[]);
if(execvp(arg_child[i][0], arg_child[i]) < 0)
{
fprintf(stderr, "%s:%d: fork() failed: %s\n", __FILE__,
__LINE__, strerror(errno));
exit(1);
}
exit(0);
/* child process exit */
}
}
/* parent process */
for(i = 0; i < count; i++)
{
/* close all pipe file descriptor */
close(pipefd[i][0]);
close(pipefd[i][1]);
}
for(i = 0; i < count; i++)
{
//pid_t waitpid(pid_t pid, int *status, int options);
waitpid(pid[i], &status, 0);
if(status != 0)
{
return status;
}
}
return status;
}
[解决办法]
使用命令重定向操作符可以使用重定向操作符将命令输入和输出数据流从默认位置重定
向到不同的位置。输入或输出数据流的位置即为句柄。
下表将列出可用的句柄。
句柄 句柄的数字代号 描述
STDIN 0 键盘输入
STDOUT 1 输出到命令提示符窗口
STDERR 2 错误输出到命令提示符窗口
UNDEFINED 3-9 这些句柄由应用程序单独定义,并且是各个工具特定的。
数字 0 到 9 代表前 10 个句柄。可以使用命令 Cmd.exe 运行程序并将该程序前 10 个
句柄中的任何一个重定向。要指定想使用的句柄,可在重定向操作符前面键入该句柄的
数字。如果未定义句柄,则默认的 < 重定向输入操作符是 0,而默认的 > 重定向输出
操作符是 1。键入 > 或 < 操作符之后,必须指定要读取或写入数据的位置。可以指定
文件名或另一个现有的句柄。
要指定重定向到现有句柄,请使用与 (&) 字符,后面接要重定向的句柄号
(例如 &句柄#)。例如,下面的命令可以将句柄 2(即 STDERR)重定向到
句柄 1(即 STDOUT):
2>&1
下表列出了可用于将输入和输出数据流进行重定向的操作符。
重定向操作符 描述
> 将命令输出写入到文件或设备(例如打印机)中,而不是写在命令提示符窗口或句柄中。
< 从文件中而不是从键盘或句柄中读入命令输入。
>> 将命令输出添加到文件末尾而不删除文件中的信息。
>& 将一个句柄的输出写入到另一个句柄的输入中。
<& 从一个句柄读取输入并将其写入到另一个句柄输出中。
[解决办法]
从一个命令中读取输出并将其写入另一个命令的输入中。也称作管道。
默认情况下,可以从键盘将命令输入(即 STDIN 句柄)发送到 Cmd.exe,然后由
Cmd.exe 将命令输出(即 STDOUT 句柄)发送到命令提示符窗口。
重定向输入 (<)
要将键盘输入重定向到文件或设备,请使用 < 操作符。例如,要从 File.txt 获取
sort 命令的输入,请键入:
sort<file.txt
File.txt 的内容将以字母顺序列表的方式显示在命令提示符窗口中。
< 操作符可以打开具有只读访问的指定文件名。所以,不能使用该操作符向文件中写入
信息。例如,如果以 <&2 启动程序,则所有试图读取句柄 0 的操作都将失败,因为句
柄 2 最初是以只写访问打开的。
注意
0 是 < 重定向输入操作符的默认句柄。
重定向输出 (>)
几乎所有的命令都将输出发送到命令提示符窗口。即使将输出发送到驱动器或打印机的
命令也会在命令提示符窗口显示消息和提示。
要将输出从命令提示符窗口重定向到文件或设备,请使用 > 操作符。可以在许多命令中
使用该操作符。例如,要将 dir 输出重定向到 Dirlist.txt,请键入:
dir>dirlist.txt
如果 Dirlist.txt 不存在,Cmd.exe 将创建该文件。如果 Dirlist.txt 存在,Cmd.exe
将使用 dir 命令的输出替换文件中的信息。
要运行 netsh routing dump 命令,然后将输出发送到 Route.cfg,请键入:
netsh routing dump>c:\route.cfg
> 操作符可以打开具有只写访问属性的指定文件。所以,不能使用该操作符读取文件。
例如,如果使用重定向 >&0 启动程序,则所有试图写入句柄 1 的操作都将失败,因为
句柄 0 最初是以只读访问打开的。
注意
1 是 > 重定向输出操作符的默认句柄。
复制句柄
重定向操作符 & 可以将输出或输入从一个指定句柄复制到另一个指定的句柄。例如,
要将 dir 输出发送到 File.txt 并将错误输出发送到 File.txt,请键入:
dir>c:\file.txt 2>&1
复制句柄时,可以复制该句柄原状态的所有特性。例如,如果一个句柄具有只写访问的
属性,则该句柄的所有副本都具有只写访问属性。不能将一个具有只读访问属性的句柄
复制到另一个具有只写访问属性的句柄。
使用 & 操作符重定向输入和副本
要将重定向输入操作符 (<) 与复制操作符 (&) 一起使用,指定的文件必须已经存在。
如果输入文件存在,Cmd.exe 将以只读方式打开该文件,然后将文件中包含的字符作为
输入发送到此命令(如同从键盘输入一样)。如果指定了句柄,Cmd.exe 将指定的句柄
复制到系统现有的句柄中。
例如,要以句柄 0 输入读取(即 STDIN)的方式打开 File.txt,请键入:
<file.txt
要打开 File.txt,并在内容排序后将输出发送到命令提示符窗口(即 STDOUT),请键入:
sort<file.txt
要查找 File.txt,然后将句柄 1(即 STDOUT)和句柄 2(即 STDERR)重定向到
Search.txt,请键入:
findfile file.txt>search.txt 2<&1
要以句柄 0 输入读取(即 STDIN)的方式复制用户定义句柄 3,请键入:
<&3
使用 & 操作符重定向输出和复制
如果将输出重定向到文件且指定了现有的文件名,Cmd.exe 将以只写方式打开文件并覆
盖该文件内容。如果指定了句柄,Cmd.exe 将文件复制到现有句柄中。
要将用户定义句柄 3 复制到句柄 1,请键入:
>&3
要将包括句柄 2(即 STDERR)的所有输出从 ipconfig 命令重定向到
句柄 1(即 STDOUT),然后将输出重定向到 Output.log,请键入:
ipconfig.exe>>output.log 2>&1
使用 >> 重定向操作符追加输出
要从命令中将输出添加到文件末尾而不丢失文件中已存在的任何信息,请使用两个连续
的大于号(即 >>)。例如,下面的命令可以将由 dir 命令生成的目录列表追加到
Dirlist.txt 文件:
dir>>dirlist.txt
要将 netstat 命令的输出追加到 Tcpinfo.txt 的末尾,请键入:
netstat>>tcpinfo.txt
使用管道操作符 (
[解决办法]
)
管道操作符 (
[解决办法]
) 可以提取一个命令的输出(默认情况下是 STDOUT),然后将其导入另
一个命令的输入中(默认情况下是 STDIN)。例如,下面的命令将对目录分类:
dir
[解决办法]
sort
在本例中,将同时启动两个命令,但随后 sort 命令会暂停,直到它接收到 dir 命令
的输出为止。sort 命令使用 dir 命令的输出作为输入,然后将输出发送到
句柄 1(即 STDOUT)。
合并带重定向操作符的命令
可以通过合并带有其他命令和文件名的筛选器命令创建自定义命令。例如,可以使用以
下命令存储包含“LOG”字符串的文件名:
dir /b
[解决办法]
find "LOG" > loglist.txt
dir 命令的输出通过 find 筛选器命令发送。包含字符串 "LOG" 的文件名作为文件名
列表(例如,NetshConfig.log、Logdat.svd 和 Mylog.bat)存储在文件
Loglist.txt 中。
要在相同命令中使用多个筛选器,请使用管道 (
[解决办法]
) 分隔筛选器。例如,下面的命令将
搜索 C 盘上的每个目录以查找包含 "LOG" 字符串的文件名,并且在命令提示符窗口中
每次显示一屏:
dir c:\ /s /b
[解决办法]
find "LOG"
[解决办法]
more
利用管道 (
[解决办法]
) 可以将 Cmd.exe 导向为通过 find 筛选器命令发送 dir 命令输出。
find 命令只选择包含字符串 "LOG" 的文件名。more 命令可以显示由 find 命令选择
的文件名(在命令提示符窗口中每次显示一屏)。有关筛选器命令的详细信息,请参阅
使用筛选器。