bash - how to pipe result from the which command to cd
You use pipe in cases where the command expects parameters from the standard input. ( More on this ).
With cd
command that is not the case. The directory is the command argument. In such case, you can use command substitution. Use backticks or $(...)
to evaluate the command, store it into variable..
path=`which oracle`
echo $path # just for debug
cd $path
although it can be done in a much simpler way:
cd `which oracle`
or if your path has special characters
cd "`which oracle`"
or
cd $(which oracle)
which is equivalent to backtick notation, but is recommended (backticks can be confused with apostrophes)
.. but it looks like you want:
cd $(dirname $(which oracle))
(which shows you that you can use nesting easily)
$(...)
(as well as backticks) work also in double-quoted strings, which helps when the result may eventually contain spaces..
cd "$(dirname "$(which oracle)")"
(Note that both outputs require a set of double quotes.)
Why doesn't the cd command work when trying to pipe it with another command
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.
why isnt it piping to the cd command?
The cd
command doesn't read standard input, so anything that you pipe to it will be ignored.
The closest to what your command is (literally) trying to do will be this:
cd `find -size 1033c`
... except that you are liable to 'cd' to a file (which will fail!) or not find a directory with that size ... leading to you (silently) cd-ing to the user's home directory.
And also your find
command is missing a directory to search!
Based on your comments, you are trying to cd
to the directory containing a file with a given size. If we can assume that there will only ever be one such file, then the following should work:
FILE=`find . -size 1033c -type f`
cd `dirname $FILE`
If there could be more than one match, then you need to do something like this ... which should cd to the directory with the first matching file.
FILE=`find . -size 1033c -type f -print -quit`
cd `dirname $FILE`
Unix: (pwd now: ~) from cd command?
When you "pipe" input from one process or job to another, you are also spawning another process. Both of these jobs are said to be "children" of main process which called them (usually the process running the terminal emulator).
# 2 process are run here
# first job: echo
# second job: ls
echo "/home/" | ls
Looking at the source for zsh
, it looks like when the cwd
of a job differs from the original cwd
of the job after execution, it will notify the user with a message like (pwd now: foo)
. This helps to ensure that the user knows exactly where the are in the directory tree, which is especially useful when they may not have intended to do so. Below is taken from jobs.c where the cwd
(referred to as pwd
) where among other things, the cwd
(referenced as pwd
) are compared before printing the (pwd now: foo)
message. If they are different the message is printed, if they are equal it is not.
if ((lng & 4) || (interact && job == thisjob &&
jn->pwd && strcmp(jn->pwd, pwd))) {
doneprint = 1;
fprintf(fout, "(pwd %s: ", (lng & 4) ? "" : "now");
fprintdir(((lng & 4) && jn->pwd) ? jn->pwd : pwd, fout);
fprintf(fout, ")\n");
fflush(fout);
}
When you pipe something into ch
you are changing the cwd
in a child process and some of the normal checks which hide this message when calling cd
directly are bipassed. Otherwise cd
words in the same way.
# changes directories into ./test
echo "test" | cd
# (pwd now: /path/to/test)
# changes directory to home
echo | cd
# (pwd now: /home/<username>)
# calling this again will not echo the message, since the cwd is already
# the home directory and no change occurs
echo | cd
As for why the cwd
is changed to the home directory (~
) it is due to how cd
behaves when no paths are given as an argument. Unlike a lot of linux commands, cd
does not read from stdin
for paths to move into. Due to this, piping into cd
will simply populate stdin
for cd
, but that content is ignored. Because of this piping into cd
is the same as just calling cd
on its own.
# these next lines produce the same behavior
echo path/to/dir/test | cd
cd
When cd
does not receive a path to move to, it will move you to your home directory (referenced on linux systems as ~
)
# each of these lines produce the same behavior
cd /home/<username>
cd ~
cd
How to pipe output of a command that expects file argument
Some programs have special handling for -
. For example, you can tell tar
to write to stdout so it can be used in a pipeline. This would create a tarball locally and untar it remotely without the tarball ever being written to disk:
tar -cf - *.txt | ssh user@host tar -C /dir/ -xf -
You can use /dev/stdout
with nearly all programs, as long as they don't need a seekable file.
command --save-to-file /dev/stdout
Can I pipe between commands, and run the programs from different directories?
command arg1 | ( cd /other_dir ; command arg2 )
(…)
executes a command in a subshell. cd
is a shell builtin command, not a 'real process'. ( cd X ; command )
will start a new sub-shell, cd into X, then run command
. command
is running as a process, but in a different directory.
Going forward it's better to have commands that can take a directory as an argument (and if not defined, default to the current working directory). Then you could have the simple solution of command arg1 | command --dir=/other_dir arg2
How would I tar extract pipe cd?
Pipes link up the output of one program to the input of another - just how a pipe sends the output from your garden tap (faucet) to your lawn sprinkler.
A minus sign (-) is a shortcut meaning either input or output - which one it means depends on position/context.
Your wget
command grabs some data from the web and, because of the -
, sends it through a pipe to tar
.
The tar
command reads that data from the pipe, because of its -
, and creates some files and directories.
The tar
command doesn't send anything down any further pipes, so there'd be nothing for cd
to read. You also don't know the name of the directory you want to go to. If you did, you could go there as a follow-up action like this:
wget ... - | tar ... - ; cd SOMEWHERE
Or you could make it conditional on the tar
command running successfully with:
wget ... - | tar ... - && cd SOMEWHERE
Piping `cd` or `popd` output prevents changing directories?
In bash
, dash
and ash
, each command in a pipeline runs in a subshell.
In zsh
, ksh
, and bash
with shopt -s lastpipe
, all except the last command in the pipeline run in subshells.
Since cd
-- as well as variables, shell options, ulimits and new file descriptors -- only affects the current process, their effects will not affect the parent shell.
Examples:
# Doesn't change directory
cd foo | cat
pwd
# Doesn't set $bar on default bash (but does on zsh and ksh)
echo foo | read bar
echo "$bar"
# Doesn't change the ulimit
ulimit -c 10000 2>&1 | grep "not permitted"
ulimit -c
The same also applies to other things that generate subshells. None of the following will change the directory:
# Command expansion creates a subshell
echo $(cd foo); pwd
# ( .. ) creates a subshell
( cd foo ); pwd
# Backgrounding a process creates a subshell
cd foo & pwd
To fix it, you have to rewrite your code to run anything that affects the environment in the main shell process.
In your particular case, you can consider using process substitution:
popd > /dev/null 2> >(toerr) && lsd
This has the additional benefit of only running lsd
when popd
is successful, rather than when toerr
is successful like your version does.
Related Topics
How to Get the Name of the Current Git Branch into a Variable in a Shell Script
Using 'Date' Command to Get Previous, Current and Next Month
Find a Pattern in Files and Rename Them
Where Are Include Files Stored - Ubuntu Linux, Gcc
Docker: Are Docker Links Deprecated
Changing Environment Variable of a Running Process
Using Software Floating Point on X86 Linux
How Have Both Local and Remote Variable Inside an Ssh Command
Mongodb Gui Client (Cross-Platform or Linux)
How to Establish Ssl Connection Upon Wget on Ubuntu 14.04 Lts
Redirecting Stdout with Find -Exec and Without Creating New Shell
Best Way to Get MAChine Id on Linux
Bash: Silently Kill Background Function Process
Negate If Condition in Bash Script
How to Check If a Program Is Run in Bash on Ubuntu on Windows and Not Just Plain Ubuntu