-1

I have 2 folders set up:

/
  folder/
    subfolder/
      file.txt
  symlink-folder/
    subfolder/ -> /folder/subfolder

If I cd /symlink-folder/subfolder then run ls, I see file.txt, as I expect. However, if I then run mv file.txt .., I end up with this:

/
  folder/
    file.txt
    subfolder/
  symlink-folder/
    subfolder/ -> /folder/subfolder

Basically, the command moved file.txt to its parent directory, not the parent directory of the shell, as I would expect. If I run pwd, I see /symlink-folder/subfolder. If I run cd .., it navigates to /symlink-folder. Both of these work as I expect.

How do I set this up?

EDIT: a bit of testing, if I navigate into /symlink-folder/subfolder then run vi ../file and save, it creates a file in the original folder's parent as well, not the shell's parent. It appears that the symbolic link itself is behaving strangely, not the command that is using it. cd works, but any other command doesn't seem to.

ewok
  • 4,091
  • 15
  • 46
  • 66

2 Answers2

2

Please read Why does ls .. show real parent content when I'm inside a symbolic link directory? and my answer there. And then this answer about cd and pwd.

A tool like your mv, your vim or ls (in the linked question) always knows its current working directory as a physical path. It could know the logical path if it examined the $PWD environment variable that should certainly be in the environment when the tool is invoked from a shell. Hardly any tool uses $PWD, the mentioned tools don't, we can say that not using $PWD is the common behavior.

Therefore for your mv .. means "the parent directory in the physical path to the current working directory".

After cd /symlink-folder/subfolder the logical path is /symlink-folder/subfolder, but the physical path is /folder/subfolder. For any tool that doesn't use $PWD .. will mean /folder. Only tools that do use $PWD will treat .. as /symlink-folder.

To make mv work as you want, you need to use $PWD one way or another. You can parse $PWD somehow and/or you can use a tool that uses the variable. The cd builtin in your shell and pwd (which may be a builtin or a separate executable) are such tools.

E.g. instead of mv file.txt .. you can do:

(cd -L .. && mv subfolder/file.txt .)

(where I used a subshell, so the current working directory of your main shell does not change). Here cd -L .. uses $PWD, but also your brain had to parse $PWD to know what string to prepend to file.txt. Such parsing can be automated, but it's quite cumbersome. If it's a one-time job then IMO using the brain for parsing is the right thing to do.

Alternatively you can do this:

mv file.txt "$(cd -L .. && pwd)"

Here cd -L .. uses $PWD and puts the subshell (executing the insisde of the command substitution) in .. according to the logical path. Then pwd prints the then-working directory (and I think ultimately it doesn't matter if it's pwd -L or pwd -P). This method does not require you to parse $PWD by hand (or rather by brain).

Another solution is to directly manipulate $PWD as a string:

mv file.txt "${PWD%/*}/"

${PWD%/*} expands to the content of $PWD without the last slash and everything after (Remove Smallest Suffix Pattern, here). This transforms /symlink-folder/subfolder into /symlink-folder. But if the current working directory was /, then the result would be an empty string which is wrong; therefore I postpend one / and in case of / I would get / (which is good because /.. means /). In our case of /symlink-folder/subfolder I get /symlink-folder/ which is as good as /symlink-folder when interpreted (by mv) as a destination directory.

This method should behave well for any $PWD. $PWD should always contain an absolute path whithout . or .. components (that could otherwise make the method misbehave).

Kamil Maciorowski
  • 69,815
  • 22
  • 136
  • 202
0

You seem to describe a non-standard behavior. The man-page symlink(7) says: "The mv(1) and rm(1) commands do not follow symbolic links named as arguments, but respectively attempt to rename and delete them".

You might be able to workaround this problem by using two commands: cp the symlink and then rm the original one.

If the implementation of cp follows the man-pages, then the following arguments of cp may help:

-d     same as --no-dereference --preserve=links

-P, --no-dereference
          never follow symbolic links in SOURCE
harrymc
  • 455,459
  • 31
  • 526
  • 924
  • I'm sure the behavior is non-standard. I'm struggling to figure out what's causing it. I haven't set up anything differently in this installation than I have in the past. I'm hoping someone can figure out what might cause this issue – ewok Jun 14 '23 at 13:19
  • The Linux distributions in WSL are heavily modified to adapt to running on top of Windows. This might change somewhat the behavior of the runtime. – harrymc Jun 14 '23 at 13:23
  • I've encountered that kind of issue in the past in a few different ways, but not this specific issue. I have WSL installed on 2 other machines and it behaves as expected. This newest installation is the one that seems to be misbehaving – ewok Jun 14 '23 at 13:25
  • Though I've noticed its not just the mv command. running `vi ../foo` results in the same issue: the file gets saved to the linked directory's parent, not the working directory's parent. So it's got to be some kind of issue with how WSL is treating symlinks – ewok Jun 14 '23 at 13:26
  • You might add the detail of what are the differences between the machines where symlinks work and don't work: Windows version and installed updates, WSL version 1 or 2 and whether installed from the Microsoft Store or not, Linux distributions and version etc. – harrymc Jun 14 '23 at 13:29
  • I'll try to do that later on. One of the machines I no longer have access to (switched jobs, old job laptop worked, new one doesn't) and the other is my PC at home, so I'll have to look at the differences when I get home – ewok Jun 14 '23 at 13:40
  • looking into the `ln` man page (https://man7.org/linux/man-pages/man1/ln.1.html) it looks like the links might be getting created with the `-r` option active, even though I'm not passing `-r` into the command? – ewok Jun 14 '23 at 14:03
  • See what info is returned by `ls -la symlinkName`. – harrymc Jun 14 '23 at 14:37
  • nothing useful I don't think: `lrwxrwxrwx 1 me me 20 Jun 14 10:03 subfolder -> /folder/subfolder ` – ewok Jun 14 '23 at 15:37
  • -1. This answer describes the behavior of `mv` or `cp` when an argument (specifically an argument passed as `SOURCE`) is a pathname of a symlink. For OP's `mv file.txt ..` this would be relevant *if `file.txt` was a symlink*, but it's not a symlink. The issue is with `..` interpreted according to the physical path (see my answer), this answer does not address this at all. Maybe you have been misled by `file.txt -> /folder/subfolder/file.txt` present in the revision 1; it suggested `file.txt` is a symlink, but in the context of the rest of the question it made no sense and it's now corrected. – Kamil Maciorowski Jun 14 '23 at 18:52