Since UNIX has all those wonderful filter-like programs (such as grep
, sed
, tr
and so forth), what's the easiest way to write one of those in standard C?
由于UNIX具有所有那些精彩的类似过滤器的程序(例如grep,sed,tr等),在标准C中编写其中一个最简单的方法是什么?
By filter, I mean a program which reads standard input, performs some manipulation of the data, and then writes it to standard output. This is useful in constructing pipelines of commands, with each performing some additional manipulation of the data, such as:
通过过滤器,我的意思是一个程序,它读取标准输入,执行一些数据操作,然后将其写入标准输出。这在构造命令管道时非常有用,每个命令都执行一些额外的数据操作,例如:
grep xyzzy input.file | tr '[A-Z]' '[a-z]' | sed 's/plugh/PLUGH/g'
(each of the |
pipe symbols connects the standard output of the previous command to the standard input of the next, hence the pipeline metaphor).
(每个|管道符号将前一个命令的标准输出连接到下一个命令的标准输入,因此是管道隐喻)。
Let's say I needed one that converted all uppercase characters to lowercase. And, yes, I realise this particular problem can be solved with the UNIX:
假设我需要一个将所有大写字符转换为小写的字符。而且,是的,我意识到这个特殊问题可以通过UNIX解决:
tr '[A-Z]' '[a-z]'
but that's just an example.
但这只是一个例子。
What I'm actually after is the simplest standard C source code to do such a filter.
我真正想要的是做这种过滤器的最简单的标准C源代码。
4 个解决方案
#1
6
You could use getline
as described by @hroptatyr, but you can do something a lot simpler:
您可以使用@hroptatyr所描述的getline,但您可以做一些更简单的事情:
#include <stdio.h>
#include <ctype.h>
int main(void) {
int c;
while ((c = getchar()) != EOF)
putchar(tolower(c));
return 0;
}
#2
3
In pseudo-code:
do
line = read(stdin);
filter(line);
print(line);
until no_more_lines
In real code:
在实际代码中:
char *line = NULL;
size_t len = 0U;
ssize_t n;
while ((n = getline(&line, &len, stdin)) >= 0) {
/* LINE is of length N, filter it */
filter(line, n);
/* print it */
fputs(line, stdout);
}
free(line);
and filter()
looks like:
和filter()看起来像:
static void filter(char *line, size_t length)
{
while ((*line++ = tolower(*line)));
}
Edit: Don't forget to define _POSIX_C_SOURCE >= 200809L
or _XOPEN_SOURCE >= 700
. And don't forget to include stdio.h
for getline()
and ctype.h
for tolower()
.
编辑:不要忘记定义_POSIX_C_SOURCE> = 200809L或_XOPEN_SOURCE> = 700.并且不要忘记为getline()包含stdio.h,为tolower()包含ctype.h。
#3
3
A "filter" program is simply a program which reads from the standard input stream (stdin
) and writes to the standard output stream (stdout
). Before writing the read data, the data is usually transformed in some way (if you don't preform any transformation or filtering, you basically wrote an cat
program which just prints out whatever is given to it). The power of filter program comes from the fact that they don't dictate where their input comes from or where the output is going to. Instead, it's up to the caller of the program to provide the input/output channels.
“过滤器”程序只是一个从标准输入流(stdin)读取并写入标准输出流(stdout)的程序。在写入读取数据之前,数据通常以某种方式进行转换(如果您不进行任何转换或过滤,您基本上编写了一个cat程序,它只打印出给它的任何内容)。过滤程序的强大之处在于它们不会决定输入来自何处或输出的位置。相反,由程序的调用者提供输入/输出通道。
The core of a filter program could look something like this (you can use this as a template for your own filter programs):
过滤器程序的核心可能看起来像这样(您可以将其用作您自己的过滤器程序的模板):
#include <stdio.h>
int filter( FILE *input, FILE *output );
int main( void )
{
const int retval = filter( stdin, stdout );
fflush( stdout );
return retval;
}
That's it. The actual work is done by a filter
function which performs the transformation you desire. For instance, here's a simple program which reads the characters from the input file, turns them to lowercase, and then prints them to the output file:
而已。实际工作由过滤功能完成,该功能执行您想要的转换。例如,这是一个简单的程序,它从输入文件中读取字符,将它们转换为小写,然后将它们打印到输出文件:
#include <stdio.h>
#include <ctype.h> /* for tolower */
int filter( FILE *input, FILE *output )
{
while ( !feof( input ) ) {
if ( ferror( input ) ) {
return 1;
}
fputc( tolower( fgetc( input ) ), output );
}
return 0;
}
int main( void )
{
const int retval = filter( stdin, stdout );
fflush( stdout );
return retval;
}
If you compile and run this program, it'll simply sit there and patiently wait for data to read from the standard input file stdin
. This file is usually bound to the console, which means that you have to enter some data by hand. However, command shells implement a feature called pipes which allow you to pipe the output of one command to the input of another. This allows composing multiple programs into a pipeline to form powerful commands.
如果您编译并运行该程序,它将只是坐在那里耐心地等待数据从标准输入文件stdin读取。此文件通常绑定到控制台,这意味着您必须手动输入一些数据。但是,命令shell实现了一个名为pipes的功能,允许您将一个命令的输出传递给另一个命令的输入。这允许将多个程序组合成管道以形成强大的命令。
Here's how we could use our filter program (assuming you called the resulting binary lower
):
以下是我们如何使用我们的过滤程序(假设您将结果二进制调用较低):
$ echo Hello | lower
hello
$
Since our filter program doesn't define where the data to be read is coming from, we can combine it with all kinds of programs producing output on stdout
. For instance, here's how you can get a whole file as lowercase (you can use type
on Windows machines instead):
由于我们的过滤程序没有定义要读取的数据的来源,我们可以将它与在stdout上产生输出的各种程序结合起来。例如,以下是如何将整个文件作为小写(您可以在Windows机器上使用类型):
$ cat myfile.txt
Hello, World!
This is a simple test.
$ cat myfile.txt | lower
hello, world!
this is a simple test.
$
#4
-4
L1:
mov dx,081
mov cx,1
mov bx,0
mov ax,03f00
int 021
cmp ax,0
je L2
cmp b[081],'a'
jb L3
cmp b[081],'z'
ja L3
sub b[081],020
L3:
mov dx,081
mov cx,1
mov bx,1
mov ax,04000
int 021
jmp L1
L2:
mov ax,04c00
int 021
; Example in A86 Assembler see eji.com for A86/D86
#1
6
You could use getline
as described by @hroptatyr, but you can do something a lot simpler:
您可以使用@hroptatyr所描述的getline,但您可以做一些更简单的事情:
#include <stdio.h>
#include <ctype.h>
int main(void) {
int c;
while ((c = getchar()) != EOF)
putchar(tolower(c));
return 0;
}
#2
3
In pseudo-code:
do
line = read(stdin);
filter(line);
print(line);
until no_more_lines
In real code:
在实际代码中:
char *line = NULL;
size_t len = 0U;
ssize_t n;
while ((n = getline(&line, &len, stdin)) >= 0) {
/* LINE is of length N, filter it */
filter(line, n);
/* print it */
fputs(line, stdout);
}
free(line);
and filter()
looks like:
和filter()看起来像:
static void filter(char *line, size_t length)
{
while ((*line++ = tolower(*line)));
}
Edit: Don't forget to define _POSIX_C_SOURCE >= 200809L
or _XOPEN_SOURCE >= 700
. And don't forget to include stdio.h
for getline()
and ctype.h
for tolower()
.
编辑:不要忘记定义_POSIX_C_SOURCE> = 200809L或_XOPEN_SOURCE> = 700.并且不要忘记为getline()包含stdio.h,为tolower()包含ctype.h。
#3
3
A "filter" program is simply a program which reads from the standard input stream (stdin
) and writes to the standard output stream (stdout
). Before writing the read data, the data is usually transformed in some way (if you don't preform any transformation or filtering, you basically wrote an cat
program which just prints out whatever is given to it). The power of filter program comes from the fact that they don't dictate where their input comes from or where the output is going to. Instead, it's up to the caller of the program to provide the input/output channels.
“过滤器”程序只是一个从标准输入流(stdin)读取并写入标准输出流(stdout)的程序。在写入读取数据之前,数据通常以某种方式进行转换(如果您不进行任何转换或过滤,您基本上编写了一个cat程序,它只打印出给它的任何内容)。过滤程序的强大之处在于它们不会决定输入来自何处或输出的位置。相反,由程序的调用者提供输入/输出通道。
The core of a filter program could look something like this (you can use this as a template for your own filter programs):
过滤器程序的核心可能看起来像这样(您可以将其用作您自己的过滤器程序的模板):
#include <stdio.h>
int filter( FILE *input, FILE *output );
int main( void )
{
const int retval = filter( stdin, stdout );
fflush( stdout );
return retval;
}
That's it. The actual work is done by a filter
function which performs the transformation you desire. For instance, here's a simple program which reads the characters from the input file, turns them to lowercase, and then prints them to the output file:
而已。实际工作由过滤功能完成,该功能执行您想要的转换。例如,这是一个简单的程序,它从输入文件中读取字符,将它们转换为小写,然后将它们打印到输出文件:
#include <stdio.h>
#include <ctype.h> /* for tolower */
int filter( FILE *input, FILE *output )
{
while ( !feof( input ) ) {
if ( ferror( input ) ) {
return 1;
}
fputc( tolower( fgetc( input ) ), output );
}
return 0;
}
int main( void )
{
const int retval = filter( stdin, stdout );
fflush( stdout );
return retval;
}
If you compile and run this program, it'll simply sit there and patiently wait for data to read from the standard input file stdin
. This file is usually bound to the console, which means that you have to enter some data by hand. However, command shells implement a feature called pipes which allow you to pipe the output of one command to the input of another. This allows composing multiple programs into a pipeline to form powerful commands.
如果您编译并运行该程序,它将只是坐在那里耐心地等待数据从标准输入文件stdin读取。此文件通常绑定到控制台,这意味着您必须手动输入一些数据。但是,命令shell实现了一个名为pipes的功能,允许您将一个命令的输出传递给另一个命令的输入。这允许将多个程序组合成管道以形成强大的命令。
Here's how we could use our filter program (assuming you called the resulting binary lower
):
以下是我们如何使用我们的过滤程序(假设您将结果二进制调用较低):
$ echo Hello | lower
hello
$
Since our filter program doesn't define where the data to be read is coming from, we can combine it with all kinds of programs producing output on stdout
. For instance, here's how you can get a whole file as lowercase (you can use type
on Windows machines instead):
由于我们的过滤程序没有定义要读取的数据的来源,我们可以将它与在stdout上产生输出的各种程序结合起来。例如,以下是如何将整个文件作为小写(您可以在Windows机器上使用类型):
$ cat myfile.txt
Hello, World!
This is a simple test.
$ cat myfile.txt | lower
hello, world!
this is a simple test.
$
#4
-4
L1:
mov dx,081
mov cx,1
mov bx,0
mov ax,03f00
int 021
cmp ax,0
je L2
cmp b[081],'a'
jb L3
cmp b[081],'z'
ja L3
sub b[081],020
L3:
mov dx,081
mov cx,1
mov bx,1
mov ax,04000
int 021
jmp L1
L2:
mov ax,04c00
int 021
; Example in A86 Assembler see eji.com for A86/D86