mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-22 20:16:12 +08:00
Add support for piping using other file descriptor than fd 1
darcs-hash:20051007140857-ac50b-314a47d98ccd09e837be7bd81ebe58d5144c3499.gz
This commit is contained in:
parent
8ff36deeb4
commit
1917ce96f4
|
@ -155,9 +155,7 @@ equivalent.
|
|||
The user can string together multiple commands into a so called
|
||||
pipeline. This means that the standard output of one command will be read
|
||||
in as standard input into the next command. This is done by separating
|
||||
the commands by the pipe character (|).
|
||||
|
||||
For example
|
||||
the commands by the pipe character (|). For example
|
||||
|
||||
<tt>cat foo.txt | head</tt>
|
||||
|
||||
|
@ -169,6 +167,17 @@ to combine commands through pipes, read the manual pages of the
|
|||
commands you want to use using the 'man' command. If you want to find
|
||||
out more about the 'cat' program, type <tt>man cat</tt>.
|
||||
|
||||
Pipes usually connect file descriptor 1 (standard output) of the first
|
||||
process to file descriptor 0 (standard input) of the second
|
||||
process. It is possible use a different output file descriptor by
|
||||
prepending it to the pipe symbol, just like you would do with normal
|
||||
IO redirections. For example:
|
||||
|
||||
<tt>make fish 2|less</tt>
|
||||
|
||||
will attempt to build the fish program, and any errors will be shown
|
||||
using the less pager.
|
||||
|
||||
\subsection syntax-background Background jobs
|
||||
|
||||
When you start a job in \c fish, \c fish itself will pause, and give
|
||||
|
|
24
exec.c
24
exec.c
|
@ -142,14 +142,14 @@ static int use_fd_in_pipe( int fd, io_data_t *io )
|
|||
if( !io )
|
||||
return 0;
|
||||
|
||||
if( (io->io_mode == IO_PIPE) ||
|
||||
(io->io_mode == IO_BUFFER) )
|
||||
if( ( io->io_mode == IO_BUFFER ) ||
|
||||
( io->io_mode == IO_PIPE ) )
|
||||
{
|
||||
if( io->pipe_fd[0] == fd ||
|
||||
io->pipe_fd[1] == fd )
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
return use_fd_in_pipe( fd, io->next );
|
||||
}
|
||||
|
||||
|
@ -256,7 +256,10 @@ static void handle_child_io( io_data_t *io )
|
|||
free_fd( io, io->fd );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
We don't mind if this fails, it is just a speculative close
|
||||
to make sure no unexpected untracked fd causes us to fail
|
||||
*/
|
||||
while( close(io->fd) == -1 )
|
||||
{
|
||||
if( errno != EINTR )
|
||||
|
@ -323,22 +326,22 @@ static void handle_child_io( io_data_t *io )
|
|||
p->pid,
|
||||
io->pipe_fd[io->fd] );
|
||||
*/
|
||||
int fd_to_dup = io->fd;//io->io_mode==IO_BUFFER?1:(io->fd?1:0);
|
||||
int fd_to_dup = io->fd;
|
||||
|
||||
if( dup2( io->pipe_fd[fd_to_dup], io->fd ) == -1 )
|
||||
if( dup2( io->pipe_fd[fd_to_dup?1:0], io->fd ) == -1 )
|
||||
{
|
||||
debug( 1, PIPE_ERROR );
|
||||
wperror( L"dup2" );
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if( fd_to_dup )
|
||||
if( fd_to_dup != 0 )
|
||||
{
|
||||
close_loop( io->pipe_fd[0]);
|
||||
close_loop( io->pipe_fd[1]);
|
||||
}
|
||||
else
|
||||
close_loop( io->pipe_fd[fd_to_dup] );
|
||||
close_loop( io->pipe_fd[0] );
|
||||
|
||||
/*
|
||||
if( close( io[i].pipe_fd[ io->fd ] ) == -1 )
|
||||
|
@ -797,9 +800,11 @@ void exec( job_t *j )
|
|||
pipe_write.fd=1;
|
||||
pipe_read.io_mode=IO_PIPE;
|
||||
pipe_read.pipe_fd[0] = -1;
|
||||
pipe_read.pipe_fd[1] = -1;
|
||||
pipe_write.io_mode=IO_PIPE;
|
||||
pipe_read.next=0;
|
||||
pipe_write.next=0;
|
||||
pipe_write.pipe_fd[0]=pipe_write.pipe_fd[1]=0;
|
||||
|
||||
//fwprintf( stderr, L"Run command %ls\n", j->command );
|
||||
|
||||
|
@ -818,6 +823,8 @@ void exec( job_t *j )
|
|||
mypipe[1]=-1;
|
||||
skip_fork=0;
|
||||
|
||||
pipe_write.fd = p->pipe_fd;
|
||||
|
||||
/*
|
||||
This call is used so the global environment variable array is
|
||||
regenerated, if needed, before the fork. That way, we avoid a
|
||||
|
@ -1269,7 +1276,6 @@ void exec( job_t *j )
|
|||
debug( 3, L"Job is constructed" );
|
||||
|
||||
j->io = io_remove( j->io, &pipe_read );
|
||||
j->io = io_remove( j->io, &pipe_write );
|
||||
|
||||
for( tmp = block_io; tmp; tmp=tmp->next )
|
||||
j->io = io_remove( j->io, tmp );
|
||||
|
|
2
parser.c
2
parser.c
|
@ -934,7 +934,7 @@ static void parse_job_main_loop( process_t *p,
|
|||
tok_get_pos( tok ) );
|
||||
return;
|
||||
}
|
||||
|
||||
p->pipe_fd = wcstol( tok_last( tok ), 0, 10 );
|
||||
p->argv = list_to_char_arr( args );
|
||||
p->next = calloc( 1, sizeof( process_t ) );
|
||||
if( p->next == 0 )
|
||||
|
|
23
proc.c
23
proc.c
|
@ -565,13 +565,22 @@ int job_do_notification()
|
|||
j->notified = 1;
|
||||
if( !j->skip_notification )
|
||||
{
|
||||
fwprintf( stdout,
|
||||
L"fish: %ls %d, \'%ls\' terminated by signal %ls (%ls)",
|
||||
proc_is_job?L"Job":L"Process",
|
||||
proc_is_job?j->job_id:p->pid,
|
||||
j->command,
|
||||
sig2wcs(WTERMSIG(p->status)),
|
||||
sig_description( WTERMSIG(p->status) ) );
|
||||
if( proc_is_job )
|
||||
fwprintf( stdout,
|
||||
L"fish: Job %d, \'%ls\' terminated by signal %ls (%ls)",
|
||||
j->job_id,
|
||||
j->command,
|
||||
sig2wcs(WTERMSIG(p->status)),
|
||||
sig_description( WTERMSIG(p->status) ) );
|
||||
else
|
||||
fwprintf( stdout,
|
||||
L"fish: Process %d, \'%ls\' from job %d, \'%ls\' terminated by signal %ls (%ls)",
|
||||
p->pid,
|
||||
p->argv[0],
|
||||
j->job_id,
|
||||
j->command,
|
||||
sig2wcs(WTERMSIG(p->status)),
|
||||
sig_description( WTERMSIG(p->status) ) );
|
||||
tputs(clr_eol,1,&writeb);
|
||||
fwprintf (stdout, L"\n" );
|
||||
found=1;
|
||||
|
|
2
proc.h
2
proc.h
|
@ -92,6 +92,8 @@ typedef struct process{
|
|||
INTERNAL_BUILTIN, \c INTERNAL_FUNCTION, \c INTERNAL_BLOCK
|
||||
*/
|
||||
int type;
|
||||
/** File descriptor that pipe output should bind to */
|
||||
int pipe_fd;
|
||||
/** true if process has completed */
|
||||
volatile int completed;
|
||||
/** true if process has stopped */
|
||||
|
|
37
tokenizer.c
37
tokenizer.c
|
@ -38,6 +38,11 @@
|
|||
*/
|
||||
#define INPUT_ERROR L"Invalid input"
|
||||
|
||||
/**
|
||||
Error string for when trying to pipe from fd 0
|
||||
*/
|
||||
#define PIPE_ERROR L"Can not use fd 0 as pipe output"
|
||||
|
||||
/**
|
||||
Characters that separate tokens. They are ordered by frequency of occurrence to increase parsing speed.
|
||||
*/
|
||||
|
@ -489,10 +494,6 @@ void tok_next( tokenizer *tok )
|
|||
switch( *tok->buff )
|
||||
{
|
||||
|
||||
case L'|':
|
||||
tok->last_type = TOK_PIPE;
|
||||
tok->buff++;
|
||||
break;
|
||||
case L'\0':
|
||||
tok->last_type = TOK_END;
|
||||
/*fwprintf( stderr, L"End of string\n" );*/
|
||||
|
@ -509,6 +510,15 @@ void tok_next( tokenizer *tok )
|
|||
tok->buff++;
|
||||
break;
|
||||
|
||||
case L'|':
|
||||
check_size( tok, 16 );
|
||||
|
||||
tok->last[0]=L'1';
|
||||
tok->last[1]=L'\0';
|
||||
tok->last_type = TOK_PIPE;
|
||||
tok->buff++;
|
||||
break;
|
||||
|
||||
case L'>':
|
||||
return read_redirect( tok, 1 );
|
||||
case L'<':
|
||||
|
@ -520,14 +530,31 @@ void tok_next( tokenizer *tok )
|
|||
if( iswdigit( *tok->buff ) )
|
||||
{
|
||||
int fd = *tok->buff - L'0';
|
||||
check_size( tok, 16 );
|
||||
switch( *(tok->buff+1))
|
||||
{
|
||||
case L'|':
|
||||
{
|
||||
if( fd == 0 )
|
||||
{
|
||||
tok_error( tok, PIPE_ERROR );
|
||||
return;
|
||||
}
|
||||
|
||||
tok->buff+=2;
|
||||
tok->last[0]=L'0'+fd;
|
||||
tok->last[1]=L'\0';
|
||||
tok->last_type = TOK_PIPE;
|
||||
return;
|
||||
}
|
||||
|
||||
case L'>':
|
||||
case L'<':
|
||||
{
|
||||
tok->buff++;
|
||||
read_redirect( tok, fd );
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
read_string( tok );
|
||||
|
|
Loading…
Reference in New Issue
Block a user