Bash: Running one command after another using string variable - linux

I understand that running one command after another is done in bash using the following command
command1 && command2
or
command1; command2
or even
command1 & command2
I also understand that a command stored in a bash variable can be run by simply firing the variable as:
TestCommand="ls"
$TestCommand
Doing the above will list all the files in the directory and I have tested that it does.
But doing the same with multiple commands generates an error. Sample below:
TestCommand="ls && ls -l"
$TestCommand
ls: cannot access &&: No such file or directory
ls: cannot access ls: No such file or directory
My question is why is this happening and is there any workaround?
And before you bash me for doing something so stupid. The preceding is just to present the problem. I have a list of files in my directory and I am using sed to convert the list into a single executable string. Storing that string in a bash variable, I am trying to run it but failing.

When you put two command in a single string variable, it is executed as single command. so when you are using "$TestCommand" to execute two "ls" commands, it is executing only one(first) "ls" command. it considers && and ls(second) as argument of first ls command.
As your current working directory is not having any files named && and ls it is returning error :
ls: cannot access &&: No such file or directory
ls: cannot access ls: No such file or directory
So, basically your commands behaves like this
ls file1 file2 -l
and it will give you output like this if file1 and file2 exists:
HuntM#~/scripts$ ls file1 file2 -l
-rw-r--r-- 1 girishp staff 0 Dec 8 12:44 file1
-rw-r--r-- 1 girishp staff 0 Dec 8 12:44 file2
Now your solution:
You can create function OR one more script to execute 2 commands as below:
caller.sh
#!/bin/bash
myLs=`./myls.sh`
echo "$myLs"
myls.sh
#!/bin/bash
ls && ls -l

Related

How to pass variable to do external action but not command parameter in bash

I want to do a output redirection in bash for passing variable in shell.
For example:
OPTION=">> /tmp/log1 2>&1"
ADD_OPTION=($OPTION)
ls ${ADD_OPTION[#]}
I want to record result of ls command in /tmp/log1.
So as to, ls >> /tmp/log1 2>&1 to be executed.
But unfortunately, ${ADD_OPTION[#]} was treated as parameter of ls.
The actual result is:
ls: >>: No such file or directory
ls: /tmp/log1: No such file or directory
ls: 2>&1: No such file or directory
What should I do for it?
You can use eval:
eval ls ${OPTION}
As an obvious note, be careful with eval.
Example:
$ OPTION=">> /tmp/log1 2>&1"
$ eval ls ${OPTION}
$ cat /tmp/log1
1
2
3
eval $(echo "ls ${ADD_OPTION[#]}")
is probably what you want to do

Why doesn't the cd command work when trying to pipe it with another command

I'm trying to use a pipeline with cd and ls like this:
ls -l | cd /home/user/someDir
but nothing happens.
And I tried:
cd /home/user/someDir | ls -l
It seems that the cd command does nothing while the ls -l will work on the current directory.
The directory that I'm trying to open is valid.
Why is that? Is it possible to pipe commands with cd / ls?
Didn't have any problem with other commands while using pipe.
cd takes no input and produces no output; as such, it does not make sense to use it in pipes (which take output from the left command and pass it as input to the right command).
Are you looking for ls -l ; cd /somewhere?
Another option (if you need to list the target directory) is:
cd /somewhere && ls -l
The '&&' here will prevent executing the second command (ls -l) if the target directory does not exist.

what is the use of running shell script like "$ ls -la | script.sh"?

To get total number of lines read, why we are using ls -la | script.sh ?
Why we cant execute normal way like script.sh ?
Note that script.sh is the shell script program.
Breaking it down bit by bit:
ls -la
List all files (including dotfiles) in long format.
|
Sends the output of the command on the left to the command on the right
script.sh
Executes the script.
So the output of ls -la will be sent via stdin to script.sh.
To get total number of lines, that is files in your case, simply
ls | wc -l

Need to run a command in current directory only if the file is not set with executable

Here is the problem:
Use a bash for loop which loops over files that have the string "osl-guest" and ".tar.gz" in your current directory (using the ‘ls’ command, see sample output below), and runs the command ‘tar -zxf’ on each file individually ONLY IF the file is not set with executable. For example, to run the ‘tar -zxf’ command on the file ‘file1’, the command would be: tar -zxf file1
Sample output of "ls -l":
-rw-r--r-- 1 lance lance 42866 Nov 1 2011 vmlinuz-2.6.35-gentoo-r9-osl-guest_i686.tar.gz
-rwxr-xr-x 1 lance lance 42866 Nov 1 2011 vmlinuz-3.4.5-gentoo-r3-osl-guest_i686.tar.gz
-rw-r--r-- 1 lance lance 42866 Nov 1 2011 vmlinuz-3.5.3-gentoo-r2-osl-guest_i686.tar.gz
You can perform the loop in the following way, without the need to call ls:
# For each file matching the pattern
for f in *osl-guest*.tar.gz; do
# If the file is not executable
if [[ ! -x "$f" ]]; then
tar -zxf $f;
fi;
done;
The *osl-guest*.tar.gz simply uses shell expansion in order to get the list of files you want, rather than making a call it ls.
The if statement checks if the file is executble, -x is the test for an executable and the use of ! negates the result, so it will only enter the if block when the file is not executable.

redirecting stdout in shell script

Either it is late in the day for me or I am missing something naive here.
here is a contrived example
#!/bin/bash
command="ls -al > check.txt"
$command
When I run this script on a shell it gives me error I guess due to the ">" operator. Anyway I can redirect the output from inside a shell script. I thought this was very straight forward:
ls -la > temp.txt
ls: cannot access >: No such file or directory
ls: cannot access temp.txt: No such file or directory
#!/bin/bash
command="ls -al"
$command > check.txt
> is a special character in Bash (and most shells). It does not belong to a command.
Here is another way to do it using eval,
#!/bin/bash
command="ls -al > check.txt"
eval $command

Resources