Function for processing pipe input

I am trying to write a bash function to return a specific line of an output stream by its number. Currently, the full command is as follows:

mdfind 'my_search_string' | sed "2q;d" 

This will return the second line of output from the mdfind command.

I am trying to turn sed "$1q;d" into a function that is assigned as an alias.

How can I handle the input channel?

+4
source share
4 answers

To return the second line of output, do the following:

 ... | sed -ne 2p 

And use it as a function:

 function print_2nd_line { sed -ne 2p } mdfind 'my_search_string' | print_2nd_line 

You can also choose shorter names, such as p2 , as you wish.

The function can also be configured to be able to print the second line from the specified files, for example:

 function print_2nd_line { sed -ne 2p -- " $@ " } print_2nd_line file ... | print_2nd_line ## Still could be used like this. 

By the way, a more efficient version will be

 sed -ne '2{p;q}' 

UPDATE

As suggested by Charles Duffy, you can also use this format for compatibility with POSIX. In fact, it is also compatible with all shells based on the original V sh system.

 print_2nd_line() { sed -ne '2{p;q}' -- " $@ " } 

In addition, if you want to pass a custom line number to your function, you can:

 print_2nd_line() { N=$1; shift sed -ne "${N}{p;q}" -- " $@ " } 

Where you can run it like:

 ... | print_2nd_line 2 ## Still could be used like this. 

or

 print_2nd_line 2 file 
+7
source

You just need to protect the variable name:

To define a function called search:

 search() { ... | sed -n "${1}p;q"; } 

but note that this is not tolerated by sed . It would be better to do

 search() { ... | sed -n "${1}{p; q;}"; } 

In fact, the original sed is not just not portable, but it doesn't do what you want! It should always end after processing line 1. If you have a sed that behaves as you describe in the question, you can double check!

+2
source

My awked bash alias:

alias second="awk 'FNR==2'"

cat file | second

or

second file

So, I don’t understand correctly, do you want to write a function that receives the number of rows to filter as a parameter? And also do you want to process the input channel in it to filter this line? Your input channel will be an argument to your function, and you can get all of them using $@ .

Sorry, I understand what OP wanted :)
As I understand it, he wants to process the input std using a shell function with parameters, i.e.

cmd | func args

So, the following works:

function sift { awk "FNR==$1" ;}

Example:

cat file | sift 2

(see comment about awk vs sed )

0
source

As an exercise - this version is in pure bash, without using any external tools:

 return_line() { local lineno=$1 while (( lineno > 1 )); do read; (( lineno-- )); done read -r && printf '%s\n' "$REPLY" } # ...to test... return_line 3 <<<$'one\ntwo\nthree\nfour' # ...and yes, this works with pipelines... printf 'one\ntwo\nthree\nfour' | return_line 3 

The purebash version will usually be faster with short input streams (or when selecting an early line from a long stream), but slower with long ones.

0
source

Source: https://habr.com/ru/post/1500307/


All Articles