163

I want to take down data in /path/to/data/folder/month/date/hour/minute/file and symlink it to /path/to/recent/file and do this automatically every time a file is created.

Assuming I will not know ahead of time if /path/to/recent/file exists, how can I go about creating it (if it doesn't exist) or replacing it (if it does exist)? I am sure I can just check if it exists and then do a delete, symlink, but I'm wondering if there is a simple command which will do what I want in one step.

drjrm3
  • 2,055

2 Answers2

218

This is the purpose of ln's -f option: it removes existing destination files, if any, before creating the link.

ln -sf /path/to/data/folder/month/date/hour/minute/file /path/to/recent/file

will create the symlink /path/to/recent/file pointing to /path/to/data/folder/month/date/hour/minute/file, replacing any existing file or symlink to a file if necessary (and working fine if nothing exists there already).

If a directory, or symlink to a directory, already exists with the target name, the symlink will be created inside it (so you'd end up with /path/to/recent/file/file in the example above). The -n option, available in some versions of ln, will take care of symlinks to directories for you, replacing them as necessary:

ln -sfn /path/to/data/folder/month/date/hour/minute/file /path/to/recent/file

POSIX ln doesn’t specify -n so you can’t rely on it generally. Much of ln’s behaviour is implementation-defined so you really need to check the specifics of the system you’re using. If you’re using GNU ln, you can use the -t and -T options too, to make its behaviour fully predictable in the presence of directories (i.e. fail instead of creating the link inside the existing directory with the same name).

Stephen Kitt
  • 434,908
  • Thanks for the elaborate answer. When a symlink already exists and is overwritten - does it happen atomically? I.e. would there be a brief time window during which the symlink doesn't exist, and programs that try to access it during this time will fail? – obe Nov 12 '22 at 16:03
  • 1
    @obe that depends on the implementation. GNU ln replaces the file atomically: it creates the new symlink using a random name, then renames it to the desired name, overwriting the existing file instead of deleting it. – Stephen Kitt Nov 13 '22 at 07:10
99

Please read the manual.

ln -sfn /new/target /path/to/symlink

$ man ln

-n, --no-dereference
treat LINK_NAME as a normal file if it is a symbolic link to a directory

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
LithiumSix
  • 1,007
  • 6
    Why is this the correct answer? – Mrchief Jun 19 '17 at 18:02
  • 14
    @Mrchief If /path/to/symlink is already a symlink to a directory, without the -n flag, you'll get the symlink created in /path/to/symlink/target instead of replacing /path/to/symlink – Flimm Jun 22 '17 at 10:42
  • 5
    Note that in macOS, this still doesn't work in some cases, for instances, when /path/to/symlink exists and is a directory, and but not a symlink. I think the only way to work around it is to run rm -rf first. – Flimm Jun 22 '17 at 10:47
  • @Flimm I don't think anyone would expect adding a flag to an ln operation to become equivalent to an rm -rf. In such a case it should fail, and be up to the user to remove a dir. – Walf Dec 08 '21 at 00:06
  • 2
    This is the correct answer because it works for both files and directories. – tishma Aug 27 '22 at 17:44
  • @Walf That was in fact exactly what I was expecting. If I specify a destination path and use the -f flag, I expect it to delete the destination path if it exists – regardless of whether it’s a file, a symlink or a directory. I do not expect it to keep the destination path in place unchanged and put the symlink inside it. Flimm’s comment here is the only confirmation I’ve been able to find that even mentions this. – Janus Bahs Jacquet Jan 30 '23 at 15:26
  • I think you missed the point there, @JanusBahsJacquet. Yes, --force/-f does replace existing files or symlinks, but not entire directory trees, and nor should it. Try it for yourself: ln -snf path/to/any/target some-existing-dir. You'll find your symlink is created inside some-existing-dir rather than replacing it. If it deleted recursively, the simple, common error case of transposing target & destination arguments would regularly cause data loss. – Walf Feb 01 '23 at 00:34
  • @Walf No, I think you missed my point: I did expect it to recursively delete the destination path, even if it’s a non-symlinked directory tree. The fact that the --force flag does nothing if the destination path is a folder was unexpected to me, especially because the man pages I looked at (for macOS) are not very clear about it – they mention unlinking “the target file” under the --force flag, but don’t specify further and only mention folders at all (in a fairly roundabout way) somewhere in a side note further down on the page. – Janus Bahs Jacquet Feb 01 '23 at 10:29
  • @JanusBahsJacquet No, I understood your point but you've placed your expectation above logic & common sense. If, after learning why it does not behave that way (trivially-invoked, catastrophic data loss, without confirmation), you still think it should behave like rm -rf (because you can't be bothered to write the latter explicitly?), then please don't write any software where users may care about their data more than you. – Walf Feb 02 '23 at 01:07
  • @Walf There are plenty of instances where a function call with a particular flag can cause catastrophic data loss without confirmation – that’s part of the risk of using terminal commands. I’m not annoyed that ln isn’t one of them, just that this fact isn’t described anywhere. It would have been perfectly clear if the man page for the flag had just said, “If the target location exists and is a file or symlink, it will be unlinked first; if it is a directory, this flag has no effect”. – Janus Bahs Jacquet Feb 02 '23 at 02:47
  • @JanusBahsJacquet I'm not sure what man page you've been reading but all the ones I have access to, on a few different platforms, explicitly mention that behaviour: "In the 3rd and 4th forms, create links to each TARGET in DIRECTORY." – Walf Feb 02 '23 at 05:14
  • I want the command to fail if the symlink already exists, so I'm thankful for -n. – David Winiecki Mar 03 '23 at 18:06
  • The manpage on my mac claims that -n is non-standard. On mac -F also exists, which appears to do what some people above seem to want: "If the proposed link ... already exists and is a directory then remove it so that the link may occur." However on my Debian 11 system there is also a -F that does something completely different: "allow the superuser to attempt to hard link directories". Also the mac manpage does not clearly state that -f refuses to remove directories, like Janus Bahs Jacquet said. The debian one reads like Walf's quote. – David Winiecki Mar 03 '23 at 18:32
  • In any case, ln seems a bit tricky, so it's probably good that it's conservative about deleting things. A user can just try again. A script should probably be more explicit anyway and use ln in the simplest way possible, and explicitly check for existence of paths and types (symlink, file, or directory), and handle each case or throw an error. – David Winiecki Mar 03 '23 at 18:34
  • Downvote because I was told to rtfm… lol… that's why I'm here… because I don't want to do that – ClintM Nov 22 '23 at 05:33