0

Starting with this directory structure:

 $ tree
.
├── 1
│   └── 2
│       └── foo.jar
└── a
    └── b
        └── c
            └── setAlias

The goal is to come up with the contents of setAlias, so I can source the file, and it will create an alias that runs java -jar /absolute/path/to/foo.jar

Here's what I have so far:

FOO="java -jar $(realpath $(dirname $_)/../../../1/2/foo.jar)"
echo "Setting Alias:"
echo "    foo -> $FOO"
alias foo='$FOO'

If I source setAlias from its own directly, everything works fine. But if I set it from the root directory, I have to run it twice before the absoulute path is resolved:

$ source a/b/c/setAlias 
realpath: ./../../../1/2/foo.jar: No such file or directory
Setting Alias:
    foo -> java -jar 

$ source a/b/c/setAlias 
Setting Alias:
    foo -> java -jar /home/MatrixManAtYrService/1/2/foo.jar

If I do this from ./a/b/c the path is resolved on the first try.

What is happening here? Why does realpath take two tries to find the file?

MatrixManAtYrService
  • 8,023
  • 1
  • 50
  • 61
  • 1
    The bash manpage has contained the following line for a *very* long time: "For almost every purpose, aliases are superseded by shell functions." IOW, do *not* use aliases. Just stop. – William Pursell Nov 15 '17 at 20:26
  • I will be sure to take that to heart. I'm not sure why i didn't think to just export a function instead. – MatrixManAtYrService Nov 15 '17 at 21:47

1 Answers1

1

This is a very strange thing to do, but it's easily explained. Here's an excerpt from man bash under Special Parameters

$_ [..] expands to the last argument to the previous command, after expansion. [...]

In other words, it refers to the last argument of the most recently executed command:

$ echo foo bar baz
foo bar baz

$ echo $_
baz

In your case, you run some arbitrary command not shown in your post, followed by source twice:

$ true foobar           # $_ now becomes "foobar"    
$ source a/b/c/setAlias # fails because $_ is "foobar", sets $_ to a/b/c/setAlias
$ source a/b/c/setAlias # works because $_ is now "a/b/c/setAlias"

In other words, your source will only work when preceded by a command that uses the value you require of $_ as its last argument. This could be anything:

$ wc -l a/b/c/setAlias  # also sets $_ to a/b/c/setAlias
4
$ source a/b/c/setAlias # Works, because $_ is set to the expected value

Maybe you wanted to get the current script's path instead?

that other guy
  • 116,971
  • 11
  • 170
  • 194
  • I had it in my head that `$_` would give me the argument to `source`, from which I could construct the path I need. It seemed to work in most cases because usually the previous command was `cd a/b/c` The post you linked to shows how to get what I was after. Thanks. – MatrixManAtYrService Nov 15 '17 at 21:48