Please note that LinuxExchange will be shutting down on December 31st, 2016. Visit this thread for additional information and to provide feedback.

Hello I have a problem, I need to create a BASH function that I can pass a stream to NOT A FILE. Here is the function: function ff() { cat /etc/group | fgrep -f "$1" }; When I run it like so

ff <( echo some_user )

I get an error saying "fgrep: /dev/fd/63: No such file or directory", instead of "some_uer:x:0:"

Much Appreciated!

asked 13 May '13, 17:49

Rocco's gravatar image

Rocco
111
accept rate: 0%




It appears that bash is closing the stream before grep gets a chance to open it; it could be caused by grep not being the first command in the pipeline. Try

function ff() { fgrep -f "$1" /etc/group; }

EDIT: Rather than the stream being closed prematurely, it appears that the way bash handles this is by connecting an unnamed pipe between <(echo user) and the first command in the pipeline, namely cat in your case, and then giving the command a filename of the form /dev/fd/n, where n is the number of the file descriptor of the pipe, in your case 63. The problem occurs because the file descriptor is not duplicated to the other commands in the pipeline, so cat has access to the stream but grep does not. The remedy is either to move the command that needs access to the stream to the beginning of the pipeline, as above, or, in the event that is not possible, to explicitly use named pipes, e.g.

mkfifo pipe
echo user >pipe &
ff pipe
rm pipe
link

answered 13 May '13, 20:19

KJ4TIP's gravatar image

KJ4TIP
464
accept rate: 12%

edited 15 May '13, 08:44

First of all (a pet peeve) let's get rid of the unnecessary invocation of cat in your function:

function ff() { fgrep "$1" < /etc/group ; }

Next, be aware that your use of that '<()' notation invokes what's called "process substitution" which executes a pipeline in a separate process and associates its stdout with a file created for the purpose; any such expression evaluates to the name of that file, so the error message you're seeing is correct.

In other words, you've presented the name of the pipeline's stdout file when what you wanted was the contents, almost as if you'd done this:

echo some_user > myTempFile
ff myTempFile

...so you may by now see that in your case you could get what you want (if a bit awkwardly) thus:

ff $(cat <( echo some_user ) ) # cat is necessary here ;->

...which, of course, makes it tempting to then do away with the process substitution trickery and simply do this:

ff $(echo some_user)

Bash's process substitution facility is way cool but maybe overkill here...

link

answered 15 May '13, 08:27

mod's gravatar image

mod
393
accept rate: 0%

But note that the -f flag makes grep expect the name of a file containing patterns, not a pattern itself. Also, since grep cat take names of files to search after the pattern file, the input redirection is unnecessary.

(15 May '13, 08:41) KJ4TIP

function ff() { read name; fgrep "$name" < /etc/group ; }; echo "user"| ff

link

answered 15 May '13, 08:46

shamilbi's gravatar image

shamilbi
112
accept rate: 0%

OK, this is the solution, based on process substitution and fgrep's -f flag:

function ff() { fgrep < /etc/group -f $1 ; }

ff <( echo some_user )
link

answered 15 May '13, 08:55

mod's gravatar image

mod
393
accept rate: 0%

edited 23 May '13, 19:21

I don't have enough points to edit or comment here, so:

Your primary problem is that, in a function, $1 refers to the first argument passed to the function, not to the the first argument passed to the calling script. You don't pass any arguments to your function, so $1 should be undefined or a null string - not what you wanted. If you run your script using bash -vx script-file arguments, then you'll see how bash is interpreting it.

For how to actually fix it, see @KJ4TIP 's answer.

link

answered 07 Jun '13, 17:53

josephj11's gravatar image

josephj11
111
accept rate: 0%

Your answer
toggle preview

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Markdown Basics

  • *italic* or _italic_
  • **bold** or __bold__
  • link:[text](http://url.com/ "Title")
  • image?![alt text](/path/img.jpg "Title")
  • numbered list: 1. Foo 2. Bar
  • to add a line break simply add two spaces to where you would like the new line to be.
  • basic HTML tags are also supported

Tags:

×16
×8

Asked: 13 May '13, 17:49

Seen: 3,586 times

Last updated: 07 Jun '13, 17:53

powered by OSQA