LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - General (https://www.linuxquestions.org/questions/linux-general-1/)
-   -   Pipe inside variable isn't working in bash (https://www.linuxquestions.org/questions/linux-general-1/pipe-inside-variable-isnt-working-in-bash-140305/)

Reginald0 01-30-2004 06:35 AM

Pipe inside variable isn't working in bash
 
Hi, folks!

See the examples:

bash$ X="ls"; $X
file1 file2 file3
*** Works correctly!

bash$ X="ls | wc"; $X
ls: |: No such file or directory
ls: wc: No such file or directory
*** Doesn't work!

How to make the last command work correctly as first?

Thanks in advance!

Reginald0

druuna 01-30-2004 07:05 AM

Both don't use correct syntax, although bash does know how to interpret the first example.

X="ls"; $X (X=ls, then execute $X, which will execute ls)
should be:
X="`ls`" ; echo $X (X is filled with the output of ls, then $X is echoed.

X="ls | wc"; $X (X= ls | wc, $X is executed. ls tries to list |, and wc is not understood.
should be:
X="`ls | wc`" ; echo $X (X is filled with the result of ls | wc, then $X is echoed)

Reginald0 01-30-2004 07:56 AM

It works like you said, but the results can be odd in some cases:

bash$ X="ls -al"; $X
total 20
drwxr-xr-x 2 root root 4096 Jan 30 11:31 .
drwxr-x--- 18 root root 4096 Jan 30 11:31 ..
-rw-r--r-- 1 root root 24 Jan 30 11:31 file1
-rw-r--r-- 1 root root 40 Jan 30 11:31 file2
-rw-r--r-- 1 root root 56 Jan 30 11:31 file3
*** Normal

bash$ X="`ls -al | grep root`"; echo $X
drwxr-xr-x 2 root root 4096 Jan 30 11:31 . drwxr-x--- 18 root root 4096 Jan 30 11:31 .. -rw-r--r-- 1 root root 24 Jan 30 11:31 file1 -rw-r--r-- 1 root root 40 Jan 30 11:31 file2 -rw-r--r-- 1 root root 56 Jan 30 11:31 file3
*** Odd

In fact I need a general solution for this case, cause the commands inside $X can vary.

mikshaw 01-30-2004 08:10 AM

The reason it's working differently, as far as I can tell, is because you are doing two different things here, or doing basically the same thing but in two different ways.

In the first example: X="ls -al"; $X
X is equal to the string "ls -al"
using the command $X is just telling bash to replace $X with "ls -a" and it runs the string as a command.

In the second example: X="`ls -al | grep root`"; echo $X
X is equal to the output of "ls -al" (notice the ` which tells bash to run its contents as a command)
In this case, $X is not the command, but rather an argument to "echo"
In addition, the first example puts out ls -al and stops there. The second example pipes the output to grep, which outputs only lines containing "root"

druuna 01-30-2004 08:21 AM

The behaviour is correct in both cases.

X="ls -al" ; $X - $X will execute a 'normal' ls -al. 'Normal' being the way you are used to when entering the ls -al command on the command line, all output lines by itself.

X="`ls -al`" - $X is one string. The echo command will display the string as is (one line). If you want to break up this line you could use printf (see man 3 printf or a book: unix/linux in a nutshell or a good book about C). But this might not work for you. You need to tailor printf for specific output (ls looks different then say ls -latr).

The following sollution works, but I only use it when absolutely neccesary:

X="ls -al | grep root"; eval $X

Reginald0 01-30-2004 09:43 AM

druuna,

You're absolutely right! You pointed me two ways to do the same thing with different results, but the last way works exactly like I want.

Many thanks!

Reginald0

sorcerer25 12-09-2015 09:56 AM

I know this is an old thread, but I got this problem now

thank you (me too) for the answer is working ...

just comment about mechanics:

to "see" why is not working when you don't use eval or bash -c (this asume that you can write in current directory ...)

PHP Code:

echo "z='ls -1 | wc -l' ; "'$z' bash -x z
z='ls -1 | wc -l'
ls -'|' wc -l
ls
cannot access |: No such file or directory
ls
cannot access wcNo such file or directory 

as you can see (on 3th line), when string is executed the pipe character will be surrounded by ' characters and that remove it special (pipe) signification
(long live bash for doing that ...)


another solution (less elegant, but who knows, someone may find it better) is:

z='ls -1 | wc -l' ; bash -c "$z"


All times are GMT -5. The time now is 04:18 PM.