mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-26 10:43:47 +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
|
The user can string together multiple commands into a so called
|
||||||
pipeline. This means that the standard output of one command will be read
|
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
|
in as standard input into the next command. This is done by separating
|
||||||
the commands by the pipe character (|).
|
the commands by the pipe character (|). For example
|
||||||
|
|
||||||
For example
|
|
||||||
|
|
||||||
<tt>cat foo.txt | head</tt>
|
<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
|
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>.
|
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
|
\subsection syntax-background Background jobs
|
||||||
|
|
||||||
When you start a job in \c fish, \c fish itself will pause, and give
|
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 )
|
if( !io )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if( (io->io_mode == IO_PIPE) ||
|
if( ( io->io_mode == IO_BUFFER ) ||
|
||||||
(io->io_mode == IO_BUFFER) )
|
( io->io_mode == IO_PIPE ) )
|
||||||
{
|
{
|
||||||
if( io->pipe_fd[0] == fd ||
|
if( io->pipe_fd[0] == fd ||
|
||||||
io->pipe_fd[1] == fd )
|
io->pipe_fd[1] == fd )
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return use_fd_in_pipe( fd, io->next );
|
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 );
|
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 )
|
while( close(io->fd) == -1 )
|
||||||
{
|
{
|
||||||
if( errno != EINTR )
|
if( errno != EINTR )
|
||||||
|
@ -323,22 +326,22 @@ static void handle_child_io( io_data_t *io )
|
||||||
p->pid,
|
p->pid,
|
||||||
io->pipe_fd[io->fd] );
|
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 );
|
debug( 1, PIPE_ERROR );
|
||||||
wperror( L"dup2" );
|
wperror( L"dup2" );
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( fd_to_dup )
|
if( fd_to_dup != 0 )
|
||||||
{
|
{
|
||||||
close_loop( io->pipe_fd[0]);
|
close_loop( io->pipe_fd[0]);
|
||||||
close_loop( io->pipe_fd[1]);
|
close_loop( io->pipe_fd[1]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
close_loop( io->pipe_fd[fd_to_dup] );
|
close_loop( io->pipe_fd[0] );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if( close( io[i].pipe_fd[ io->fd ] ) == -1 )
|
if( close( io[i].pipe_fd[ io->fd ] ) == -1 )
|
||||||
|
@ -797,9 +800,11 @@ void exec( job_t *j )
|
||||||
pipe_write.fd=1;
|
pipe_write.fd=1;
|
||||||
pipe_read.io_mode=IO_PIPE;
|
pipe_read.io_mode=IO_PIPE;
|
||||||
pipe_read.pipe_fd[0] = -1;
|
pipe_read.pipe_fd[0] = -1;
|
||||||
|
pipe_read.pipe_fd[1] = -1;
|
||||||
pipe_write.io_mode=IO_PIPE;
|
pipe_write.io_mode=IO_PIPE;
|
||||||
pipe_read.next=0;
|
pipe_read.next=0;
|
||||||
pipe_write.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 );
|
//fwprintf( stderr, L"Run command %ls\n", j->command );
|
||||||
|
|
||||||
|
@ -818,6 +823,8 @@ void exec( job_t *j )
|
||||||
mypipe[1]=-1;
|
mypipe[1]=-1;
|
||||||
skip_fork=0;
|
skip_fork=0;
|
||||||
|
|
||||||
|
pipe_write.fd = p->pipe_fd;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This call is used so the global environment variable array is
|
This call is used so the global environment variable array is
|
||||||
regenerated, if needed, before the fork. That way, we avoid a
|
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" );
|
debug( 3, L"Job is constructed" );
|
||||||
|
|
||||||
j->io = io_remove( j->io, &pipe_read );
|
j->io = io_remove( j->io, &pipe_read );
|
||||||
j->io = io_remove( j->io, &pipe_write );
|
|
||||||
|
|
||||||
for( tmp = block_io; tmp; tmp=tmp->next )
|
for( tmp = block_io; tmp; tmp=tmp->next )
|
||||||
j->io = io_remove( j->io, tmp );
|
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 ) );
|
tok_get_pos( tok ) );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
p->pipe_fd = wcstol( tok_last( tok ), 0, 10 );
|
||||||
p->argv = list_to_char_arr( args );
|
p->argv = list_to_char_arr( args );
|
||||||
p->next = calloc( 1, sizeof( process_t ) );
|
p->next = calloc( 1, sizeof( process_t ) );
|
||||||
if( p->next == 0 )
|
if( p->next == 0 )
|
||||||
|
|
23
proc.c
23
proc.c
|
@ -565,13 +565,22 @@ int job_do_notification()
|
||||||
j->notified = 1;
|
j->notified = 1;
|
||||||
if( !j->skip_notification )
|
if( !j->skip_notification )
|
||||||
{
|
{
|
||||||
fwprintf( stdout,
|
if( proc_is_job )
|
||||||
L"fish: %ls %d, \'%ls\' terminated by signal %ls (%ls)",
|
fwprintf( stdout,
|
||||||
proc_is_job?L"Job":L"Process",
|
L"fish: Job %d, \'%ls\' terminated by signal %ls (%ls)",
|
||||||
proc_is_job?j->job_id:p->pid,
|
j->job_id,
|
||||||
j->command,
|
j->command,
|
||||||
sig2wcs(WTERMSIG(p->status)),
|
sig2wcs(WTERMSIG(p->status)),
|
||||||
sig_description( 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);
|
tputs(clr_eol,1,&writeb);
|
||||||
fwprintf (stdout, L"\n" );
|
fwprintf (stdout, L"\n" );
|
||||||
found=1;
|
found=1;
|
||||||
|
|
2
proc.h
2
proc.h
|
@ -92,6 +92,8 @@ typedef struct process{
|
||||||
INTERNAL_BUILTIN, \c INTERNAL_FUNCTION, \c INTERNAL_BLOCK
|
INTERNAL_BUILTIN, \c INTERNAL_FUNCTION, \c INTERNAL_BLOCK
|
||||||
*/
|
*/
|
||||||
int type;
|
int type;
|
||||||
|
/** File descriptor that pipe output should bind to */
|
||||||
|
int pipe_fd;
|
||||||
/** true if process has completed */
|
/** true if process has completed */
|
||||||
volatile int completed;
|
volatile int completed;
|
||||||
/** true if process has stopped */
|
/** true if process has stopped */
|
||||||
|
|
37
tokenizer.c
37
tokenizer.c
|
@ -38,6 +38,11 @@
|
||||||
*/
|
*/
|
||||||
#define INPUT_ERROR L"Invalid input"
|
#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.
|
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 )
|
switch( *tok->buff )
|
||||||
{
|
{
|
||||||
|
|
||||||
case L'|':
|
|
||||||
tok->last_type = TOK_PIPE;
|
|
||||||
tok->buff++;
|
|
||||||
break;
|
|
||||||
case L'\0':
|
case L'\0':
|
||||||
tok->last_type = TOK_END;
|
tok->last_type = TOK_END;
|
||||||
/*fwprintf( stderr, L"End of string\n" );*/
|
/*fwprintf( stderr, L"End of string\n" );*/
|
||||||
|
@ -509,6 +510,15 @@ void tok_next( tokenizer *tok )
|
||||||
tok->buff++;
|
tok->buff++;
|
||||||
break;
|
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'>':
|
case L'>':
|
||||||
return read_redirect( tok, 1 );
|
return read_redirect( tok, 1 );
|
||||||
case L'<':
|
case L'<':
|
||||||
|
@ -520,14 +530,31 @@ void tok_next( tokenizer *tok )
|
||||||
if( iswdigit( *tok->buff ) )
|
if( iswdigit( *tok->buff ) )
|
||||||
{
|
{
|
||||||
int fd = *tok->buff - L'0';
|
int fd = *tok->buff - L'0';
|
||||||
|
check_size( tok, 16 );
|
||||||
switch( *(tok->buff+1))
|
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'>':
|
||||||
case L'<':
|
case L'<':
|
||||||
|
{
|
||||||
tok->buff++;
|
tok->buff++;
|
||||||
read_redirect( tok, fd );
|
read_redirect( tok, fd );
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
read_string( tok );
|
read_string( tok );
|
||||||
|
|
Loading…
Reference in New Issue
Block a user