如何编写输入和输出重定向程序<;f1.txt>;c中的f2.txt

如何编写输入和输出重定向程序<;f1.txt>;c中的f2.txt,c,linux,terminal,operating-system,exec,C,Linux,Terminal,Operating System,Exec,我试着做类似的事情,但被卡住了,不知道该往哪个方向走。我甚至尝试使用fork(),然后将任务分别分配给子任务和父任务,但这种情况下的重定向无法按预期工作 #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/types.h> #include<fcntl.h> int main() { execlp("cat","&

我试着做类似的事情,但被卡住了,不知道该往哪个方向走。我甚至尝试使用fork(),然后将任务分别分配给子任务和父任务,但这种情况下的重定向无法按预期工作

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<fcntl.h>
int main()
{
    execlp("cat","<","f1.txt",">","f2.txt",NULL);
    return 0;
}
#包括
#包括
#包括
#包括
#包括
int main()
{
execlp(“cat”,“”,“f2.txt”,NULL);
返回0;
}

好吧,重定向是一种shell功能

我不明白你想做什么。但要实现你正在尝试的目标,你需要跑步

sh -c 'cat < f1.txt > f2.txt'

注意:函数的第三个参数包含在两组引号中
“…”
。这是一项要求。否则,shell的空间分割将破坏它,并仅将cat作为命令字符串传递。

在Linux和其他POSIXy操作系统中,标准输入对应于文件描述符0(
stdinu FILENO
),标准输出对应于文件描述符1(
STDOUT\u FILENO
),标准错误对应于文件描述符2(
STDERR\u文件号

标准文件句柄
stdin
stdout
stderr
是标准的C抽象,在Linux中是在这些文件描述符之上实现的

若要重定向标准输入、输出或错误,首先需要获取一个打开的文件描述符,使其指向要从/重定向到的任何对象。对于文件,可通过返回文件描述符编号的函数执行此操作。然后,使用该函数将其复制(复制)到所需的描述符

考虑以下
示例.c

//SPDX许可证标识符:CC0-1.0
#定义_POSIX_C_源200809L
#包括
#包括
#包括
#包括
#包括
#包括
/*将oldfd复制到newfd,然后关闭oldfd。
在错误情况下,尝试关闭两个描述符。
如果成功,则返回0,否则返回错误代码(未设置errno)。
*/
静态内联int-move_描述符(int-oldfd,int-newfd)
{
如果(oldfd==-1 | | newfd==-1){
如果(oldfd!=-1)
关闭(oldfd);
如果(newfd!=-1)
关闭(新FD);
返回errno=EBADF;
}
如果(oldfd==newfd)
返回0;
if(dup2(oldfd,newfd)=-1){
const int saved_errno=errno;
关闭(oldfd);
关闭(新FD);
返回errno=saved\u errno;
}
如果(关闭(oldfd)=-1){
const int saved_errno=errno;
关闭(新FD);
返回errno=saved\u errno;
}
返回0;
}
/*将消息写入标准错误,保持errno不变。
这是异步信号安全的。
如果成功,则返回0,否则返回错误代码。
*/
静态内联int-wrerr(常量字符*msg)
{
const char*end=(msg)?msg+strlen(msg):msg;
if(end==msg)
返回0;
const int saved_errno=errno;
while(msg0){
msg+=n;
}否则
如果(n!=-1){
errno=已保存\u errno;
返回EIO;
}否则
如果(错误号!=EINTR){
const int retval=errno;
errno=已保存\u errno;
返回返回;
}
}
errno=已保存\u errno;
返回0;
}
静态内联无效错误消息(常量字符*名称,常量字符*原因)
{
Wrrr(姓名);
wrerr(“:”);
wrerr(原因);
Wrrr(“.\n”);
}
int main(int argc,char*argv[])
{
int-fd;
if(argc<4 | | |!strcmp(argv[1],“-h”)| |!strcmp(argv[1],“-help”)){
常量字符*arg0=(argc>0&&argv&&argv[0]&&argv[0][0])?argv[0]:“(此)”;
Wrrr(“\n”);
wrerr(“用法:”;wrerr(arg0);wrerr([-h |--help]\n”);
wrerr(“”);wrerr(arg0);wrerr(“输入输出命令[参数…]”\n);
Wrrr(“\n”);
返回退出失败;
}
fd=打开(argv[1],仅限O|rdo|NOCTTY);
如果(fd==-1){
错误消息(argv[1],strerror(errno));
返回退出失败;
}
if(移动描述符(fd,标准文件号)){
错误消息(argv[1],strerror(errno));
返回退出失败;
}
fd=打开(argv[2],O|u WRONLY | O|u CREAT,0666);
如果(fd==-1){
错误消息(argv[2],strerror(errno));
返回退出失败;
}
if(移动描述符(fd、标准输出文件号)){
错误消息(argv[2],strerror(errno));
返回退出失败;
}
if(strchr(argv[3],“/”)
execv(argv[3],(char*const*)(argv+3));
其他的
execvp(argv[3],(char*const*)(argv+3));
错误消息(argv[3],strerror(errno));
返回退出失败;
}
move\u descriptor()
只是
dup2()
close()
的一个包装。我包含它是为了演示如何安全地移动描述符(复制和关闭旧的描述符),并进行充分的错误检查

wrerr(msg)
函数类似于
fputs(msg,stderr)
,只是它直接使用文件描述符接口(),完全绕过了C stderr流抽象。它也是*,这意味着您可以在信号处理程序中使用它

*:从技术上讲,人们可能会争论
strlen()
是否是异步信号安全的。在使用glibc、newlibc或avr libc的Linux中,它是

许多Linux/Unix/POSIXy错误消息使用“filename:error message”格式。由于
wrerr()
函数只接受一个参数,因此我将
错误消息(filename,message)包括在内
helper函数打印此类错误消息。这种将常用任务拆分为helper函数的方法使代码更易于阅读,也更易于维护

程序本身至少有四个命令行参数。(第一个参数,
argv[0]
,是命令本身。第一个参数是
argv[1]
。例如,如果您以
/example arg1 arg2 arg3
的形式编译并运行它,则
argv[0]==”/examp>
execlp( "sh", "-c", " 'cat < f1.txt > f2.txt' ", NULL);