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

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.

Related

ssh tail with nested ls and head cannot access

am trying to execute the following command:
$ ssh root#10.10.10.50 "tail -F -n 1 $(ls -t /var/log/alert_ARCDB.log | head -n1 )"
ls: cannot access /var/log/alert_ARCDB.log: No such file or directory
tail: cannot follow `-' by name
notice the error returned, when i login to ssh separately and then execute
tail -F -n 1 $(ls -t /var/log/alert_ARCDB.log | head -n1 )"
see the below:
# ls -t /var/log/alert_ARCDB.log | head -n1
/var/log/alert_ARCDB.log
why is that happening and how to fix it. am trying to do this in one line as i don't want to create a script file.
Thanks a lot
Shell parameter expansion happens before command execution.
Here's a simple example. If I type...
ls "$HOME"
...the shell replaces $HOME with the path to my home directory first, then runs something like ls /home/larsks. The ls command has no idea that the command line originally had $HOME.
If we look at your command...
$ ssh root#10.10.10.50 "tail -F -n 1 $(ls -t /var/log/alert_ARCDB.log | head -n1 )"
...we see that you're in exactly the same situation. The $(ls -t ...) expression is expanded before ssh is executed. In other words, that command is running your local system.
You can inhibit the shell expansion on your local system by using single quotes. For example, running:
echo '$HOME'
Will produce:
$HOME
So you can run:
ssh root#10.10.10.50 'tail -F -n 1 $(ls -t /var/log/alert_ARCDB.log | head -n1 )'
But there's another problem here. If /var/log/alert_ARCDB.log is a file, your command makes no sense: calling ls -t on a single file gets you nothing.
If alert-ARCDB.log is a directory, you have a different problem. The result of ls /some/directory is a list of filenames without any directory prefix. If I run something like:
ls -t /tmp
I will get output like
file1
file2
If I do this:
tail $(ls -t /tmp | head -1)
I end up with a command that looks like:
tail file1
And that will fail, because there is no file1 in my current directory.
One approach would be to pipe the commands you want to perform to ssh. One simple way to achieve that is to first create a function that will echo the commands you want executed :
remote_commands()
{
echo 'cd /var/log/alert_ARCDB.log'
echo 'tail -F -n 1 "$(ls -t | head -n1 )"'
}
The cd will allow you to use the relative path listed by ls. The single quotes make sure that everything will be sent as-is to the remote shell, with no local expansion occurring.
Then you can do
ssh root#10.10.10.50 bash < <(remote_commands)
This assumes alert_ARCDB.log is a directory (or else I am not sure why you would want to add head -n1 after that).

Need help using the pipe command in terminal (Linux / shell file)

Doing an assignment for class that needs to be done using commands in the terminal. I have a shell file (temp1.sh) created in the home directory, and a shell file (temp2.sh) created in a folder (randomFolder). When I run temp2.sh I need to display the amount of characters in temp1.sh. I need to use the pipe command to accomplish this.
So I figure I need to change directory to the home directory then open the file temp1.sh and use thewc -c command to display the characters. I have been trying many different ways to execute this task and somehow can't get it to work. Any help would be appreciated. Without using a pipe I can get it to work, but I can't seem to write out this command line properly while using a pipe.
What I have done so far:
cd ~
touch temp1.sh
chmod 755 temp1.sh
echo 'This file has other commands that are not relevant and work' >> temp1.sh
mkdir randomFolder
cd randomFolder
touch temp2.sh
chmod 755 temp2.sh
echo cd ~ | wc -c temp1.sh >> temp2.sh
This last line tells me there is no such file "temp1.sh" after I run it. if I redirect to home then type wc -c temp1.sh, I get the desired output. I want this output to happen when I run temp2.sh.
Example without using pipe command:
echo wc -c ~/temp1.sh >> temp2.sh
This gives me the desired output when I run temp2.sh. However I need to accomplish this while using the pipe command.
Your code is close to working. The first part is fine:
cd ~
touch temp1.sh
chmod 755 temp1.sh
echo 'This file has other commands that are not relevant and work' >> temp1.sh
mkdir randomFolder
cd randomFolder
touch temp2.sh
chmod 755 temp2.sh
All of that should work. You problem is this part:
echo cd ~ | wc -c temp1.sh >> temp2.sh
You need to separate the cd ~ from something that runs some command and pipes the output to wc, and get the whole lot stored in temp2.sh. That could be something like:
echo "cd $HOME" > temp2.sh
echo "cat temp1.sh | wc -c" >> temp2.sh
The key point here is using separate lines for the cd command and the wc command. Using > for the first command ensures that you don't have stray garbage from previous failed attempts in temp2.sh. You can achieve the same result in multiple ways, including:
echo "cd; cat temp1.sh | wc -c" > temp2.sh
echo "cd ~; while read -r line; do echo "$line"; done < temp1.sh | wc -c" > temp2.sh
And then, finally, you need to execute temp2.sh. You might use any of these, though some (which?) depend on how your PATH is set:
./temp2.sh
temp2.sh
sh temp2.sh
sh -x temp2.sh
$HOME/randomFolder/temp2.sh
~/randomFolder/temp2.sh

How is $() different from redirection?

Im learning the commandline from the book The Linux command line and I have a doubt.
Should not
ls -l $(which cp)
and which cp | ls -l have the same output?
Because I'm taking the output of which cp and passing it to ls -l
But that does not work as expected. which cp | ls -l instead displays the contents of pwd
ls doesn't care what's in the standard input.
echo anything | ls -l
^^^
Since you haven't provided a directory to list, it will list the pwd.
In the first case ls is receiving the result as an argument, in the second it is receiving it in the input stream (stdin), wich is ignored in this case.
You can convert from the input stream to arguments using xargs :
which cp | xargs ls -l

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

Write a bash script that lists all files and subdirectories

I want to write a easy script shell like that:
#!/bin/bash
from_directory="first_directory"
to_directory="second_directory"
rsync --archive $(from_directory) $(to_directory) | ls -R $(to_directory)/$(from_directory)
OR
cp -r $(from_directory) $(to_directory) | ls -R $(to_directory)/$(from_directory)
I have this error ==> ls: impossible to reach in / home / jilambo / week2 / shooter_game: no file or directory of this type.
In the second time, it's ok because the first_directory have been copied to the segond directory.
Thanks.
As pointed out in comments, you probaly want this.
#!/bin/bash
from_directory="first_directory"
to_directory="second_directory"
rsync --archive $from_directory $to_directory; ls -R $to_directory/$from_directory
And if $from_directory and $to_directory are both absolute paths, $to_directory/$from_directory does not make sense. Might as well just do ls -R $to_directory.

Resources