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 |
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) |
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. |
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" |
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 |
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 |
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:
(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. |