Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get argument from pipe

Tags:

bash

pipe

xargs

Consider having the results from the pipe:

find .

Now I would like to access in the second command behind the pipe what is actually piped (inputed) and then for example to print it twice.

find . | printf $arg$arg\n
#each filename would be printed twice per line

Please note that the question is not asking about printing whatever once gets from pipe twice, I know how to use bash for loop or write a script that could accomplish the mentioned. How I can get $arg to use it quickly in inline scripts?

$0 and $1 do not work as they do in scripting files.

like image 612
Dávid Natingga Avatar asked Jul 25 '13 00:07

Dávid Natingga


People also ask

Can you use pipe in shell script?

Pipe may be the most useful tool in your shell scripting toolbox. It is one of the most used, but also, one of the most misunderstood. As a result, it is often overused or misused. This should help you use a pipe correctly and hopefully make your shell scripts much faster and more efficient.

How do you pipe the output of a command to another command?

You can make it do so by using the pipe character '|'. Pipe is used to combine two or more commands, and in this, the output of one command acts as input to another command, and this command's output may act as input to the next command and so on.

How do you pipe a grep output?

grep is very often used as a "filter" with other commands. It allows you to filter out useless information from the output of commands. To use grep as a filter, you must pipe the output of the command through grep . The symbol for pipe is " | ".


3 Answers

Ignoring the possibility that file names contain newlines, you can use sed as pringley suggests in his answer, or you can create a while loop with the read command:

find . |
while read -r line
do
    echo "$line$line"
done

(The -r is for 'raw' input; it stops the shell expanding backslash escape sequences in the input, and is a standard POSIX feature of the read command in the shell.)

Since you mention bash, you can avoid problems with newlines in the file names by using the find . -print0 option to terminate each name by a null byte ('\0' in C) instead of a newline, and then use:

find . -print0 |
while read -r -d '' line
do
    echo "X${line}${line}X"
done

The -d '' replaces the normal newline delimiter with the first character of the string argument, but the string is empty so the first character is the only character is a null byte.

There isn't an easy way (nor, as far as I know, a hard way) to use a for loop along the lines of:

for line in $(find .)
do
    echo "X${line}${line}X"
done

which works reliably for names with spaces, or newlines in them.

Often, you may want to use the xargs command. This reads standard input and creates a command line using what's read from standard input as arguments to the command.

find . | xargs wc -l

Or, with newline and space safety (by default, xargs splits arguments at spaces, tabs and newlines):

find . -type f -print0 | xargs -0 wc -l

There are a lot of options you can apply to xargs — especially the GNU version.

However, you also have options to find that largely make xargs redundant:

find . -type f -exec wc -l {} +

which does basically the same job as the find . -print0 | xargs -0 wc -l command. One difference is that if there are no files in the output from find, then using -exec won't execute wc at all, whereas by default, xargs will execute it once (with no file name argument; this is for POSIX compliance). With GNU xargs, you can use -r or --no-run-if-empty to stop that happening. Mac OS X xargs seems to do that anyway.

like image 100
Jonathan Leffler Avatar answered Oct 16 '22 04:10

Jonathan Leffler


Short answer: You can print each file twice using sed:

find . | sed 's/.*/& &/'

Sed can edit lines as they are inputted. The above command says s (substitute) .* (the entire line) & & (with itself, twice).

Longer answer: When you pipe one program into another, you're connecting the first program's standard output stream to the second program's standard input stream. Anything the first program prints will be treated as input for the second program.

Unfortunately for your example, the input doesn't come in line-by-line chunks that map nicely to a hypothetical $args variable. It comes in a big monolithic stream. If you want to print each line of the stream twice, you can use sed (which is a Stream EDitor), but it's just doing line-by-line replacements.

like image 32
Pringley Avatar answered Oct 16 '22 04:10

Pringley


find . | xargs -I{} printf "%s%s\n" {} {}
like image 4
glenn jackman Avatar answered Oct 16 '22 05:10

glenn jackman