Hacker News new | past | comments | ask | show | jobs | submit login
I always forget the argument order of the `ln -s` command (reddit.com)
252 points by pepsi_can on Dec 8, 2010 | hide | past | favorite | 123 comments



I used to have this problem. Then I realized that if I want to really copy a file, I type

$cp file_from file_to

and that

$ln -s link_from link_to

has a very similar effect to the cp command above. I haven't messed this up ever since.


This phrasing confused me more.

`$ ln -s link_from link_to` would imply the reverse behavior. How does a symlink point from the actual file to the thing-that-looks-like-a-file-but-is-really-a-symlink? The file doesn't even know whether there are symlinks pointing to it.

Applying your definitions of "link from" and "link to", this:

<a href="http://google.com/>Google</a>;

creates a link from google.com to the hyperlink on your site.

I find the top reddit comment:

    cp existing new
    ln -s existing new
much, much more useful. You want to create a new link pointing to an existing file, which has the same ordering as when you use cp to create a new file with the content of an existing file.


Less ambiguously:

  cp    existing_thing new_thing
  ln -s existing_thing new_thing


That's exactly how I remember it too

  ln -s 'the one that exists' 'the one that doesnt exist'
I actually say that to myself as I'm typing the command. Since I started doing that, I've never gotten it wrong.


I say in my head "link symboliicaly from HERE to THERE"

It took me a long time till I realized that saying it thus made me always recall it properly.


I used to have this problem too, and then I read the linked article and now remember the relationship between ln and cp and never got it wrong since.

Also I wonder how many people can say the same thing as the article and still get upvoted.


I said it in fewer words and didn't add any adsense junk.


The problem with "from" and "to" is - which is the from and which is the to?

Is the "from" the file/dir I want to copy "to" a link?

Or is the "from" the name of a link I want to point "to"?

The dual meaning of some terms that the concept of links and making links creates causes a lot of this confusion, IMHO. Are we using terminology that refers to the act of creating the link or that refers to the direction of the link?

Similarly, I don't think it helps that the usage text and manpage for ln refer to "target"s.

(I know what you mean by your examples but I wanted to share my pet theory as to why this is always so hard to remember)


"to" is an entity that doesn't exist yet.


Exactly! The rule is for that commands of two letters in length (cp, ln, mv) the file on the end is the one that gets created. For commands of three letters in length (tar, zip) the file that gets created is the first one. And then there's the exceptions that prove the rule like scp and ssh.

And people say Linux isn't user-friendly! :)


It's so similar to cp that GNU cp has

  cp -l from to


Good, but cp -l is for hard links and cp -s is for symlinks. Most of the time people want the latter.


I used to just cheat. I normally cd-ed to the directory I wanted the link in then just let the name of the link be the name of the file, so I didn't need a destination file name, just ln -s source_file


In my experience the more variable argument often comes last, presumably for easy reuse. For example...

  $chown user1 file1
  $chown user1 file2

  $ln -s file1 file2
  $ln -s file1 file3
...seems more likely than...

  $chown user1 file1
  $chown user2 file1

  $ln -s file1 file2
  $ln -s file3 file2


That's the reason behind a most of the argument orders in the Haskell standard library: To ease Currying.


Why did you do that? Now I really want to implement a const and flip for text arguments :)


That could be a nice command line tool. Please include a Data.Function.on, and find a way to make it useful.

flip would actually be quite useful for me on grep. I often search the some corpus of text, but change the pattern.


This happens to be the first comment in the thread on Reddit.


Exactly. Why the GP's comment is currently at +33 when all it does is restate the main point of the story in a confusing way (by introducing from/to into the mix) is beyond me.


Probably because most of the people upvoting him didn't bother to read the story.

I am often guilty of this myself. At first I used to read all of the stories that were linked to on HN, along with the comments. But I quickly learned that the comments were often much more interesting/useful than the stories themselves.

So now I just look at the comments first, by default. And only in exceptional cases do I actually bother to read the article. There's just not enough time..

HN is an overwhelming firehose of information even without reading every article that seems interesting. But reading the comments can usually quickly give you a good feel for whether the story is worth reading or not. In this particular case, I think not.


Not the most helpful of advice for those that can't remember which way round the cp command takes its arguments either...


That's what I would have intuitively thought. But I swear it worked the other way sometimes!


Does anyone know why C calls like 'strcpy' and 'strcat' are the opposite of this?

  strcat(target, source)
  strcpy(target, source)
But, in SH...

  cp source target

I feel like these things were developed around the same time, by the same community. I've always wondered if there was a reason for the different perspective.


The reason strcat, strcpy have the destination first is because of the need to support a variable number of arguments. By definition, if the number of arguments is variable, they must be at the end. So if you think of sprintf for instance, the destination has to be first. Now, to be consistent, strcat has to behave the same and have the destination first as well, although it doesn't have a variable number of arguments.


I'm pretty sure strcpy et al pre-date the introduction of varargs. Besides, there's no reason the format string couldn't be the last argument of printf, except the specific technical detail that C requires at least one mandatory argument in any variadic function (the variable's address is used to locate the optional arguments in the stack.)


On a machine's runtime stack, there is no indication of how many parameters were passed to the function (at least on x86). C functions must use one of the mandatory arguments to determine how many arguments were pushed on the stack. In the case of the printf-family of functions, it's the number of format specifiers, e.g., "%d".


Someone once said to "What you have, then what you want" which made ALL of these easier to remember for me. In the case of strcat/cpy I think it still follows: I have an empty string 'target' and I'd like it to be 'source'.


Probably in order to be consistent with assignment.


Which is really the odd ball. In a left-to-right language, it's sort of bizarre that we don't write `4 = x' since the rvalue tends to be the more complicated part of the expression.

The curious bit is, AT&T assembly syntax does follow this convention so you'll see something like `mov $5, ax'.


Indeed. Assignment should really look like something like this this:

  expression -> variable;


Forth uses

  expression memory-location !
to store and

  memory-location @
to read.


I think it's more to do with the requirement that mandatory arguments have to go before optional ones (it wouldn't work the other way round).


In strcpy, memcpy and partners, both arguments are (rather obviously) mandatory...


Similar confusion arises from the AT&T and Intel syntaxes for x86 assembly which differ in the order of operands:

Intel:

mov bx, 100

AT&T:

mov $100, %bx

http://en.wikipedia.org/wiki/X86_assembly_language#Syntax


This is a crime against usability IMO. Another comment mentioned that tar takes arguments as "target source" rather than "source target".

Ever notice that for everything in the world that screws, like valves or screws or bottle caps, counter-clockwise loosens and clockwise tightens? How is it we got the whole world to agree on that convention, but software is 50/50 on how we order the source and destination?


My first car (a 1967 Dodge Monaco) had 'backwards' lug nuts on the left hand side of the car...

http://en.wikipedia.org/wiki/Lug_nut#History

Propane tanks also used to have backwards screwing connections. I believe this was a safety 'feature' given the mainstream use of small propane tanks. Having them tighten counter-clockwise prevents similar looking but wrong hoses from being attached to the tank. It also tricked people who didn't understand propane tanks form being able to remove a connection (since they would usually just tighten it further).


Cars generally still do have backwards nuts on the LHS. Something about vibration and direction of turn. Some of the other bolts on the LHS can be that way too.

Same with some of the LP gas cylinders I have encountered here in Aus.


Nah. I used to change tyres for a living and I never came across a car with backwards nuts on either side.


I have heard that other manufacturers originally starting using reverse-thread propane fittings to work around a 1896 Primus patent, and the situation has simply persisted.


tar is like that because of command lines

tar [args] [one thing] [list of things]

it'd be wierd if it was

tar [args] [list of things] [filename]

... but i will admit i frequently make that mistake.


tar is actually

  tar [args] [list of things]
where [args] may contain [-f filename], among other things.

That is, the destination filename is an optional argument; by default tar outputs to a tape device or stdout, depending on the implementation.

At least in GNU tar, the target filename can very well be specified as the last argument:

  tar -c foo.txt bar.txt baz.txt -f stuff.tar


good point!


But, as a counterpoint, if you want to copy several things to a folder, you do:

  cp [args] [list of things] [destination folder]


But you can also do

  cp [args] -t [destination folder] [list of things]
The same is true of mv. This is useful if you are piping filenames to xargs.


Thanks! I always wondered what was the purpose of -t. Never occurred to me it was to allow you to reverse the order of args.


I don't feel it's a crime. For that matter, I don't even prefer one over the other.

For "mv A B"

I've no problem saying either

  mv into A the contents of B
or

  mv the contents of A into B


Who does prefer one over the other? The lack of consistency is the real problem.


Except volume dials.


I conclude from this, by process of logical inference, that "louder" must be a type of "tighter".

"Forward" is also "tighter", apparently.


And sometimes doorknobs, but those are abstract enough you wouldn't expect them to behave the same. Unless you're talking about screwing the dial itself clean off.


And gas valves.


C calls are trying to mirror the assignment statement in the programming language: target := source

"cp" is trying mirror how we do things in real life: if you want to take some things from one place and put them in another, you first pick them all up (hence the first argument), walk over to the destination, and then put them down.


I suspect strcat and strcpy were parameterized as such to match memcpy.

Why memcpy was parameterized in that order, I am not certain.


memcpy(lvalue, rvalue, size)

lvalue == write location rvalue == read location

It comes from assignment syntax where the left hand side is the target of the assignment and the right hand side is the source. So this makes a ton of sense in C.

OTOH, the Bourne shell was built independent of the C programming language. The Bourne shell inherited a bit from its predecessor the Thompson shell which introduce the concept of command piping. In this case, all operations followed the pattern of data flowing to the right. This is the opposite of how assignment works in all programming languages where data flows to the left.

That's why shell commands generally move data from left to right based on their argument ordering.

FWIW, tar is unique because tar wasn't meant to do archiving to files. If you just did `tar c directory' it would archive the directory to a tape device. The `f' flag is there to redirect the output to a file (instead of the default tape device). So `tar cf foo.tar directory' is not backwards, it just uses an unusual argument convention. The modern form would be `tar --file=foo.tar create directory'.


It's similar to all the file I/O functions that always have the file descriptor first (fprintf etc). These are the heart of Unix. Remember the Unix philosophy: Everything is a file.*

* for a slightly smaller definition of everything than in Plan9


I always think that you get strcpy by first writing

   *target = source*
Step two is realizing that things don't work that way in C. Step three is sprinkling in semantic sugar to make it work.

strcat, then, is for symmetry with strcpy.


Possibly for consistency with functions that take varargs, e.g. sprintf


Most assemblers have fx

  mov a,b
as from b to a.


I've always used complex numbers as a mnemonic: real + imaginary, a + bi (obviously the file is real and the softlink is "imaginary").

http://en.wikipedia.org/wiki/Complex_number


The real/imaginary concept is exactly what I use too. I sort of recall being able to use the real/imaginary concept with other Unix commands as well, but I can't recall which ones off the top of my head.


rm only has the real component before you issue it and the imaginary one afterwards ;)


You can create multiple links with the original names at once with commands like:

  ln -s path1/files* path2/
or

  ln -s path1/* .
Doing that helped me remember the order because I knew my command could end with a directory as the destination and links would be created there.

Sometimes hardlinks are useful too. You don't always need -s

Edit: Why was this downvoted? I didn't see anyone else mention it until after my post and to me this was an easier way to remember the order than comparing it to "cp".


My god, this thing always keeps biting me. It seems so obvious now with that cp-mnemonic. But it makes me wonder, why does everyone do it wrong in the first place?


At least for me, it's because I say in my head "link $FOO to $BAR", which must be typed "ln -s $BAR $FOO".


My theory is that we're used to see symlinks as part of the "ls -l" output, which lists the link name first, and then the target. Later, we want to create symlinks as we're used to see them (linkname -> target).


The problem is that you're using the wrong definition of "link". I also say "link $foo to $bar", but that puts it in the right order:

I have a folder. I want to link that folder to some other name, over yonder. " ln -s foo bar". See?


Because in the final result, the link points to the original. The directory listing will even say

    link -> original
So naturally you want to say that in the command, "make a link that points to the original".

I had a friend who gave up and made an alias that sorted out which of the arguments existed and did The Right Thing.


"I want to make a symbolic <link> to this <source>"

"I want to copy this <source> to this <destination>"

vs.

"I want this <source> to be accessible via this <link>"


For me, it's always the recursive options in (s)cp and chown/chmod and which one is capital -R which one is lower case -r. Simply vexing.


Yeah this one is particularly annoying.


That's funny, I do too. I always thought it was just me...


It is never just you. An important lesson I learned while programming.


The way I remember it is "ln -s target [filename]", where filename is an optional argument to override the default, where the default is a link created in the CWD pointing to target. Easy.


Yup. The thought process is basically "the target is optional, so it has to go last".


Why don't we have better shells that give hints on these things?

I'm thinking like an IDE will pop up some help text when you begin typing a function name or a recognised special word. Why doesn't the standard sh (bash for me) give me similar help, as I type "ln" it could give me a pop-up with the possible completions and then as I get to "ln -s" it could remind me with "TARGET [NAME] // will create a file named NAME that is a soft link to TARGET, or use TARGET's name if NAME isn't specified". You get the picture.

In a pure text env the help could appear on the next line highlighted appropriately or could be to the right of the cursor or somesuch.

I'm hoping someone will say $CONSOLE does that already ...? Anyone?


It's mostly for historical reasons. More specifically we have restricted shell as text mode only tool, and intellisense-like features/inline help do not tend themselves neatly to line/character based output.

I think that there could be a place for a modern, more graphical orinted command-line interface. In addition to inline help it could display tables more nicely, maybe even allow proportional fonts. And while we are changing stuff, then maybe the object passing idea could be taken from PowerShell.


It could still be text-based if it uses ncurses. For instance, something like bpython: http://bpython-interpreter.org/screenshots/


Yeah, the UNIX ln command is full of trouble.

* The arguments order is just the opposite of common sense. It has taken me years to really remember it, and I still have to think a little every time I use it.

* The default is to create hard link, which you almost never want. And if you do want them, you are probably doing it wrong. Making hard links is just asking for trouble.

I've read that Plan9 has somewhat corrected this whole problem. At least there is no ln command at all. Instead one uses bind, mount, and unmount. Of which bind is most similar to ln -s, but with arguments in reversed order.


I stopped remembering what the order was and just use the `lns` script found here: http://interglacial.com/~sburke/pub/lns.html


Same here. lns is always one of the first things I install on a new system.


The annoying thing is that the mklink command in Windows uses the opposite order, so you have to do

mklink link_to link_from

EDIT: formatting.


The worst part with that kind of mistakes is that you end up never knowing for sure. :)

You start with "ln -s A B" and realize you always make the mistake, so you force yourself to do the opposite of your natural instinct: "ln -s B A". It works until this becomes natural but you still think you always get it wrong, so start doing the opposite of your new natural: "ln -s A B". You'll now be very confused until you force yourself to learn it for good.

This happens to me all the time for various binary things.


Someone told me 'fact before fiction' a long time ago, and I've never forgotten it.


I just read the -s as "source" even though it really means symbolic.

ln -s source fakename


Think about boobs.

Everyone prefers real to fake*

  ln -s real fake
Now you will never forget.

* Yes, I realise this isn't strictly true


I used to get this wrong all the time too. Mentally, I'd be thinking "ln -s source destination", where source was the link and destination was what it pointed to. Of course, that's completely backwards. 'man ln' on OSX didn't help either, since they use the terminology 'source_file [target_file]' which just re-inforced my incorrect thinking (target sounds like something that is pointed to, does it not?).

As other people have mentioned, thinking of it in terms of the files created (ala cp) has helped to learn the correct behavior. I think this is a case where some minor change in the documentation might help to avoid the whole problem.


If you leave off the second argument, you don't need to remember it. Much easier.


That's how I finally got it right. Now I just remember that the second arg ("dest") is optional.


I think the source of confusion is that linking is closely associated with chains. When you add a link to a chain you always add the new link to the existing chain or

ln -s new_link (onto) existing(chain)

Obviously the target isn't a chain but the association between links and chains is a strong one.

In other words I don't think of creating a link as creating something new _from_ something that already exists, I think of it as adding something new _to_ something that already exists.


As someone who always had that problem, I think it's because I always mentally picture a command as saying "do <action> from <arg0> to <arg1>", ie, "copy this file to that file". But this construct doesn't hold up for linking, so I just have to remember it arbitrarily by remembering cp. function(src, dest) just generally seems to be the unofficial "right way" of ordering things.


Its like a black hole in my mind. Every single time I screw this up. I've.... just had to learn to live with deleting my first crappy link. :)


I think up to the 100th time reading the man page I would forget, until I memorized the following mantra:

    ln -s target link_name


Same here, I just memorized "target [the] link name".


I just remind myself that second argument is optional (and it couldn't be the other way around for that to work)


In CP/M the order really was "cp to from". So chosen to match the assignment operator in programming.


Every comment except this one is just a repeat of the stuff said in the original reddit discussion


My mnemonic for this is to remember that the link name is optional. When you specify only one argument the link name is the base name of the target (in the current working directory). Therefore the link name must be the second argument.


Imagine there's an arrow pointing left between the arguments. You know - "the symlink is pointing to this file".

ln -s file <== symlink

Always remember that. Pointing left. The symlink is pointing at the file.


My mneumonic is that in "ln" the "n" comes second, and n is for "name" so the name of the symlink comes second. But I still have to think about it every time...


a copy points to the original (for an instant anyway) the same way that a link points to the original:

  cp original copy

  ln -s original link


The way I think of it is that the path that exists first (the target file), comes first.

It's kind of a dumb way to think of it, but it seems to work for me.


I also occasionally forget the -s, and really wish it was the default since I'm almost always creating a symbolic link.


Could you maybe add:

alias ln='ln -s'

to your .bashrc? A quick test of this in my terminal and the alias takes precedent over the ln command. Although, I guess it'd be worth doing a few tests to make certain!


Sure, but I'd rather not get bitten when I'm on a system where I don't have that alias defined.


when I noticed that I was messing up when using ln, I started thinking this way: "write what you already know first, so you have time to think about what you'll write next

"what you already know" being the existing file and the second part being the name of the link to the existing file.

I never got it wrong again.


Ruby's alias_method(new_name, old_name) always gets me also because I'm so used to ln [-s] (src, tgt).


The arguments are in order they appear. i.e. alias_method :alias, :method

But yeah, it's weird that it's opposite of ln.


A co-worker once told me to remember it like: "I have a (src) that I'd like to call (dst)"


My mneumonic is "lentil", since it's ln (-s) <T-for-target> <L-for-link>.


I always forget the argument order of the `ln -s` command...

...because I met the `man` command.


Ditto. I just remember that it's the reverse of tar, but the cp trick is better.


Funny, I have a similar problem with scp.


I just think of the "-s" as "source".


"ln -s something somewhere"


think like so: ln -s {source} {target}

(not "from"/"to", which is ambiguous)


Keepin' it real fake...

ln -s real fake


$ ln -s javac javac

Not like that.


remember real first fake second ...


ln -s source destination


exist want

from to

source target


It's the same argument order for mv and cp, also the same for rsync and scp

Hell, it's even the same argument order for git-clone.

Pretty much all command lines use "source destination" order.

Why is 'ln' confusing? Because people think of "linking" in a backwards way, it seems that if you're creating a link from A -> B, A is the source and B is the destination. But that's not the meaning of "source destination" that command lines expect

  mv B A
A is the new B

  cp B A
A is the new B, but B is still there

  ln -s B A
A is the new B, except it's just a link, and yes, B is still there.

B is the source, A is the destination. B is the source of the data, A is the destination for that data; the command will create 'A' (or modify it), that's why it's the destination.

For the link itself, B is the destination, but for the operation of creating the link, B is the source, and that's the meaning that's consistent with all other commands.


I use emacs and dired as a condom that shields me from the stupidity that is remembering this kind of trivia.


Yeah it seems backwards to me as well. I always thought it was the only one.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: