But something about the syntax is perplexing and counter to what I would expect.
The arguments for ln
, in the form that you're using it, are:
ln [OPTION]... [-T] TARGET LINK_NAME (1st form)
The perplexing, unintuitive thing is that when you're creating a symlink, the target argument for ln
isn't expected to be a path to a file, but rather the contents of the symlink to be created. If you think about it for a moment, it's obvious that it has to be that way. Consider:
$ echo foo >foo
$ ln -s foo bar1
$ ln -s $PWD/foo bar2
$ cat bar1
foo
$ cat bar2
foo
$ ls -l bar1 bar2
lrwxrwxrwx 1 matt matt 3 Dec 29 16:29 bar1 -> foo
lrwxrwxrwx 1 matt matt 29 Dec 29 16:29 bar2 -> /home/matt/testdir/foo
In that example I create 2 symlinks, named "bar1" and "bar2", that point to the same file. ls
shows that the symlinks themselves have different contents, though - one contains an absolute path, and one contains a relative path. Because of this, one would continue working even if it were moved to another directory, and the other wouldn't:
$ mv bar2 /tmp
$ cat /tmp/bar2
foo
$ mv bar1 /tmp
$ cat /tmp/bar1
cat: /tmp/bar1: No such file or directory
So, considering that we must be able to make both relative and absolute symlinks, and even to create broken symlinks that will become un-broken if the target file is later created, the target argument has to be interpreted as freeform text, rather than the path to an already-existing file.
If you want to create a file named deploy/resources.php that links to deploy/resources.build.php, you need to decide if you want to create an absolute symlink (which is resilient against the symlink being moved, but breaks if the target is moved), or a relative symlink (which will keep working as long as both the symlink and the target are moved together and maintain the same relative paths).
To create an absolute symlink, you could do:
$ ln -s $PWD/deploy/resources.build.php deploy/resources.php
To create a relative one, you would first figure out the relative path from the source to the target. In this case, since the source and target are in the same directory relative to one another, you can just do:
$ ln -s resources.build.php deploy/resources.php
If they weren't in the same directory, you would need to instead do something like:
$ ln -s ../foo/f bar/b
In that case, even though foo
and bar
are both in your current directory, you need to include a ../
into the ln
target because it describes how to find f
from the directory containing b
.
That's an extremely long explanation, but hopefully it helps you to understand the ln
syntax a little better.
Best Answer
The choice of the title of your question is a bit confusing.
pushd
/popd
, acsh
feature copied bybash
andzsh
, are a way to manage a stack of remembered directories.pushes the current working directory onto a stack, and then changes the current working directory (and then prints
/some/dir
followed by the content of that stack (space-separated).prints the content of the stack (again, space separated) and then changes to the top element of the stack and pops it from the stack.
(also beware that some directories will be represented there with their
~/x
or~user/x
notation).So if the stack currently has
/a
and/b
, the current directory is/here
and you're running:pushd
will print/tmp/whatever /here /a /b
andpopd
will output/here /a /b
, not/tmp/whatever
. That's independent of using command substitution or not.popd
cannot be used to get the path of the previous directory, and in general its output cannot be post processed (see the$dirstack
or$DIRSTACK
array of some shells though for accessing the elements of that directory stack)Maybe you want:
Or
Though, I'd use:
In any case,
pushd "$(mktemp -d)"
doesn't runpushd
in a subshell. If it did, it couldn't change the working directory. That'smktemp
that runs in a subshell. Since it is a separate command, it has to run in a separate process. It writes its output on a pipe, and the shell process reads it at the other end of the pipe.ksh93 can avoid the separate process when the command is builtin, but even there, it's still a subshell (a different working environment) which this time is emulated rather than relying on the separate environment normally provided by forking. For example, in
ksh93
,a=0; echo "$(a=1; echo test)"; echo "$a"
, no fork is involved, but stillecho "$a"
outputs0
.Here, if you want to store the output of
mktemp
in a variable, at the same time as you pass it topushd
, withzsh
, you could do:With other Bourne-like shells:
Or to use the output of
$(mktemp -d)
several times without explicitly storing it in a variable, you could usezsh
anonymous functions: