26

Supposing I am in the same folder as an executable file, I would need to type this to execute it:

./file

I would rather not have to type /, because / is difficult for me to type.

Is there an easier way to execute a file? Ideally just some simple syntax like:

.file

or something else but easier than having to insert the / character there.

Perhaps there is some way to put something in the /bin directory, or create an alias for the interpreter, so that I could use:

p file
  • 9
    Maybe swap / with another key using xmodmap? So at least it's easier to type – Guy Feb 6 '17 at 10:09
  • 26
    As a side note, / is used extensively in Unix, largely as a directory separator. You are probably better off finding an easier way to type it. – chrylis Feb 7 '17 at 9:30
  • 7
    @RossPresser This question makes very little sense since . and ./ at the beginning of the file are two completely different meanings for technical reasons any beginner should know. / is not difficult to type for the vast majority of people, and if OP has an injury which prevents this, they should consider alternate keyboard layouts, since there is no way they can avoid / completely while in the terminal. – JFA Feb 7 '17 at 19:56
  • 1
    @JFA The majority of keyboard layouts used in continental Europe as well as South America put / on shift-7 which is comparatively difficult to type, even without an injury. – nitro2k01 Feb 8 '17 at 13:37
  • 6
    Edit history: "why cant Network Interface be simply instructed to make all internet queries through a remote host via ssh on port 22." ಠ_ಠ – Derek 朕會功夫 Feb 8 '17 at 17:18

11 Answers 11

35

It can be "risky" but you could just have . in your PATH.

As has been said in others, this can be dangerous so always ensure . is at the end of the PATH rather than the beginning.

  • 1
    Don't really see how that's "risky": my path has been that way since long before linux, and it has never caused the slightest problem. – jamesqf Feb 6 '17 at 18:41
  • 21
    @jamesqf It is risky because if you cd to a directory that is world writable and try to use a command that is not in your path, you might execute a (possibly malicious) executable by the same name that someone wrote to that path. This is much worse if you put . at the beginning of your path. In that case, a malicious executable called ls would be executed if you try to call ls in that directory. – bytesized Feb 6 '17 at 18:59
  • 2
    Please avoid this, for the reasons specified above. The p command would be better. – Guido Feb 7 '17 at 0:22
  • 11
    @jamesqf When it's "your" system, and only you use it, it's not so bad. The problem comes (and has tripped many a Unix admin over the years) on multi-user system. With a . early in the PATH, all a malicious user needs to do is drop a fake ls command in their directory and persuade the admin to "look at something weird" and they've got root access. – TripeHound Feb 7 '17 at 12:10
  • 1
    Good solution, although it won't work if the file happens to be named test, as in the question's title (since test is a shell built-in, and probably also exists somewhere in your $PATH already). – yellowantphil Feb 9 '17 at 5:03
71

. will auto-complete to ./ (type . and press Tab) at least in modern Bash shells, so you shouldn't have to use a complex or insecure (like PATH modification) solution.

If it doesn't auto-complete you might need to install the "bash-completion" package.

  • Are you sure? . has multiple completion candidates: . (current dir), .. (parent dir), the . command (which bash provides a nonstandard alias source for), and any dotfiles present. Maybe the bash-completion package ignores this; I find it atrociously annoying (e.g. it makes it impossible to tab-complete dir names in a make command line and is generally awful with makefiles full of implicit rules) so I always purge it. – R.. Feb 7 '17 at 3:41
  • 3
    I tried it, and yes, it does auto-complete this way. In almost every case that's what a regular user would want: I don't think I've ever seen a dotfile which should be executable, running something in a subdirectory is vastly more common than running something in a parent directory, and IMO it does a damn good job of finding make targets. – l0b0 Feb 7 '17 at 8:09
  • With bash 3.2 it does not autocomplete. Could this be new in bash 4? – Calimo Feb 8 '17 at 16:21
  • 2
    @Calimo More likely new in recent versions of bash-completion. It's far from a fundamental change. – l0b0 Feb 8 '17 at 18:14
42

or.. perhaps giving the interpreter an alias in the bashrc file and then simply

   p  file

It is possible to write such a function:

p() {
 ./"$@"
}

in your ~/.bashrc. Then you'll be able to run p app arguments instead of ./app arguments. This solution works for executables of any type, including scripts and binaries.

"$@" expands to appropriately quoted list of arguments passed to the function (preserving all special characters from glob or variable expansion), and, as @Scott pointed out, bash is clever enough to prepend ./ to the first one of them, preserving the rest.

  • Although it's less general for running app under another command, like strace -f p app to see system calls made, or $(which time) p app to see how long it takes. p as a executable script would work better in these two specific examples I contrived. Neither solution could work with ldd p app, albeit ldd also differs in requiring a full path, perhaps for reasons like this. – sourcejedi Feb 6 '17 at 11:23
  • Yes, replacing p app args with ./app args in a way which is invisible to anyone would require piping shell input through some kind of preprocessor and would cause all sorts of fun when substitution occurs in an unintended place :) – aitap Feb 6 '17 at 11:26
  • 1
    In this case, shouldn't there be no quotes around $@? Otherwise it will just pass one big argument to the program. – Kroltan Feb 6 '17 at 14:58
  • 7
    @Kroltan No. $@ is an array. When expanded within ", each parameter expands to a separate word. $* behaves the way you're thinking. – 8bittree Feb 6 '17 at 15:59
  • 3
    I believe that you’ve made this unnecessarily complex, and that p() { ./"$@"; } is all you need. – Scott Feb 7 '17 at 7:01
11

You could put . to your $PATH by adding e.g. PATH=$PATH:. to your /etc/profile, this way you can execute file just by writing file, unless it is in some other folder in your path (e.g. /usr/bin/). Note that this is generally not a good idea.

Why it's bad: Say you're in a situation where you don't fully trust the contents of a directory - you've downloaded it from somewhere dodgy and you want to investigate it before running it, or you're a sysadmin helping some user by looking in their home directory, etc. You want to list the directory, so you try to type ls, but oops, you make a typo, and ended up typing sl instead. The author of this malicious directory anticipated this and put a shell script in it called "sl" which runs 'rm -rf --no-preserve-root /' (or something more malicious like installing a rootkit).

(Thanks @Muzer for the explanation)

  • 13
    Though I wholehartedly agree, It's probably woth explaining exactly why this isn't a good idea. – ymbirtt Feb 6 '17 at 10:33
  • 16
    Why it's bad: Say you're in a situation where you don't fully trust the contents of a directory - you've downloaded it from somewhere dodgy and you want to investigate it before running it, or you're a sysadmin helping some user by looking in their home directory, etc. You want to list the directory, so you try to type ls, but oops, you make a typo, and ended up typing sl instead. The author of this malicious directory anticipated this and put a shell script in it called "sl" which runs 'rm -rf --no-preserve-root /' (or something more malicious like installing a rootkit). – Muzer Feb 6 '17 at 10:45
  • 2
    Worth explaining that if the current directory is at the beginning of $PATH, instead, the attacker could just override ls or other common commands – Délisson Junio Feb 7 '17 at 4:13
  • @Muzer Huuuge tinfoil hats here. – Sombrero Chicken Feb 7 '17 at 18:23
  • 4
    @GillBates It's the sort of thing you would need to be wary of as a sysadmin who has to deal with actual and potentially malicious users, or someone who analyses suspicious archives for a living. If neither of those apply, then I agree with you. I still don't think it's a good habit to get into, though, because you never know when your circumstances will change, you get one of these jobs, and you'll endlessly curse yourself for having trained yourself to rely on insecure behaviour ;) – Muzer Feb 7 '17 at 20:56
10

You can call the interpreter, for example

bash test

In this case, the script will run even if it has neither a shebang line (eg #!/bin/bash) nor an executable bit. You will have to know the correct interpreter to run it also. You could read the shebang line of the file first to make sure you call the correct interpreter, for example if the shebang line says

#!/usr/bin/env python3

you would call

python3 test
  • 7
    interpreter just interpret code, they won't run binary files – Mc Kernel Feb 6 '17 at 10:15
  • This answer is somewhat logical because perhaps the interpreter can be given an alias in the bashrc file. – user214467 Feb 6 '17 at 10:15
  • 5
    @McKernel good point, it only works if there is an interpreter, not for compiled executables – Zanna Feb 6 '17 at 10:19
  • 2
    there is an interpreter for compiled executables: /lib/ld.so – Dmitry Kudriavtsev Feb 8 '17 at 1:26
7

As far as I know, there is no way to achieve it unless you include file in env path, so you could run it just typing: file

.file won't work since that is a different file name. It is a file called .file and not ./file.

I sense that slash may be difficult to type for you because non-english layout, maybe? In that case, it also happens to me, so I frequently swap my keyboard layout to english by pressing Alt+Shift in Windows (I use Linux from ssh)

7

People have suggested adding . to PATH, which is dangerous because it creates a risk that you will accidentally run a malicious program planted in a world-writable directory.  But, if you have executable programs in a few directories that you own and are writable only by you, then it’s safe (fairly safe?) to put those director(ies) into PATH, by adding a line like

PATH=$PATH:~/dev/myprog1:~/dev/myprog2

to your ~/.bashrc file.  Of course this means that you can run a program from one of those directories from anywhere in the filesystem.  For example, you could cd /etc and type foo, and it would run ~/dev/myprog1/foo.  This has the minor drawback that you can’t have programs by the same name in more than one of the directories.  Specifically, if you have programs called foo in both ~/dev/myprog1 and ~/dev/myprog2, you won’t be able to run the second one except by specifying a path.  Likewise if you have a ~/dev/myprog1/cat — but why would you want to?


Another approach, if you have just a few programs that you do this with, is to define aliases for them:

alias gizmo='./gizmo'
alias gonzo='./gonzo'

Or you can call the aliases .gizmo and .gonzo if you find that more intuitive.

Actually, this has, to an extent, the same security risk as putting . into your PATH.  If a malicious user can read your .bashrc and see your aliases, then he might put malware called gizmo and gonzo in random directories in the hopes that you will run it.  It’s better to make these use absolute pathnames:

alias gizmo='~/dev/myprog1/gizmo'
alias gonzo='~/dev/myprog2/gonzo'

By the way, you should avoid naming an executable test, because that is a shell builtin command, and you can run a program by that name only by specifying a path or some other trick.

  • Alternatively you can make a recipe (if you use Makefiles that is) and do make gizmo or make gonzo. – ihato Feb 7 '17 at 16:29
  • I’m sorry, but I’m not sure I understand how that relates to the question or my answer.  Are you suggesting that the OP create a Makefile in each directory, such that the actions for make gizmo end by running gizmo?  (1) That seems like an awkward way of doing the same thing as the p function, suggested in the question, initially implemented by aitap, and refined by Scott.  (2) Can you pass arguments that way?  ISTM that make gizmo arg1 arg2 is equivalent to make gizmo; make arg1; make arg2. – G-Man Feb 7 '17 at 17:51
  • 1
    (1) Perhaps my assumption is wrong but it isn't clear to me OP wants eschew from using ./ in every directory. In my mind, he's developing something and just needs to run the produced program ./file often. I really can't think of any other scenario where one would frequently need to run a local file and if he isn't running it frequently he'd not bother asking the question (he said difficult not impossible) (2) not really but you can pass the arguments in the recipe. – ihato Feb 7 '17 at 19:10
  • (1) Well, I guess we can agree that the OP’s motivation and the scope of his question are unclear. (2) Thanks for the link. – G-Man Feb 7 '17 at 21:25
3

To expand on Zanna's answer about interpreters (sorry, no rep for a comment): an "interpreter" for native executables (aka binary ELF files) is the dynamic loader (ld.so), but it typically does not understand the syntax you want:

$ /usr/lib/ld-linux-x86-64.so.2 program
program: error while loading shared libraries: program: cannot open shared object file
$ /usr/lib/ld-linux-x86-64.so.2 ./program
<program is launched>

(also, unless you symlink ld.so into your path, you'd still need to write /s)

  • This is Linux-specific, right? Could you please explain this more, why this works? I thought the (Linux) kernel would do the parsing and deciding whether and how to run a binary, that's what binfmt_misc is for. – phk Feb 6 '17 at 17:48
  • 2
    @phk The file is Linux-specific, but the concept of a dynamic linker/loader is not. For instance, FreeBSD has its very own /libexec/ld-elf.so.1. On Linux, it's not as simple as "deciding how to run a binary": binfmt_misc detects format of the file by magic numbers (ELF, shebang script, CIL). After that, binfmt_elf handler is called. It parses ELF headers and sections; .interp section contains path of the dynamic loader; this loader is started by the kernel, does relocations, and jumps to _start. On FreeBSD (not sure about others) there's no binfmt, but the principle is +/- similar. – bacondropped Feb 7 '17 at 1:05
  • 1
    @phk as to why this works -- ld.so doesn't have .interp and is statically linked, which means it doesn't need for another dynamic linker/loader to resolve its external symbols and do relocation math. – bacondropped Feb 7 '17 at 1:22
  • ISTR Solaris also has something equivalent to this. – G-Man May 8 '17 at 4:52
3

If we're allowed to start configuring things

mkdir -p ~/.local/bin
cat > ~/.local/bin/x << 'EOF'
#!/bin/sh
N="$1"
shift
exec "./$N" "$@"
EOF
chmod a+x ~/.local/bin/x

Most modern distros include ~/.local/bin in $PATH already (add export PATH="$HOME/.local/bin:$PATH" to your ~/.profile if yours doesn't). Then you can use x file to run ./file.

Don't try to define a . command. The command . script already runs script in the current shell. This allows script to define environment variables for the current shell.

  • 3
    I think there may be a good suggestion in here, but there's no explanation of what any of this does. I could work it out, but an inexperienced user would have no chance. – IMSoP Feb 6 '17 at 10:54
  • There is no need to shift $1. Just exec "$@". – reinierpost Feb 7 '17 at 9:23
  • $ (ln -s /bin/ls my-ls && exec my-ls) # bash: exec: my-ls: not found – sourcejedi Feb 7 '17 at 12:14
  • (1) There is no need to shift $1; just exec ./"$@". (2) Since you’re talking about a shell script, it’s a little pointless/misleading to advise people not to define a . command,  since it’s impossible to create a file called .. (It is possible, and very inadvisable, to define an alias or shell function called ..) – Scott Feb 9 '17 at 5:54
1

If we're allowed to make helper scripts, you could make a helper that adds the pwd to the PATH, then run

. pathhelper    #adds pwd to path
file            #now it can be run without ./

This avoids adding "." to the path and polluting your .profile with every path you might at some point want to run something in.

We can take this approach a step further by making a helper that launches a new shell with a modified PATH. If it takes a directory as a parameter (using the pwd as a default), it would function like a pushd that edits the path. You might have to be mindful that any changes to other environment variables would be lost when exiting the subshell, but in a long-running shell your PATH variable won't get all cluttered up. Depending on your workflows this might be advantageous.

:outer shell prompt$; subshellpathhelper    # launches a subshell with modified PATH
: subshell prompt $ ; file                  # in the subshell it can be run without ./

But I guess if you wanted to run with it you could hack pushd and popd so they can make the same modifications to the path without without making a subshell which will lose other changes.

pushd --path ~/some/path/    # normal pushd plus adds target to path
file                         # it can be run without ./ until you popd

(You can't do the same with cd because it doesn't have an analog to popd.)

You could also make a dedicated pair of helpers to just push and pop PATH entries. What works best really depends on your usage patterns.

  • Actually, you could do something like it in cd, but it's further out there: Make a file like .dircmds, and hack cd to make the commands defined in ./.dircmds unavailable right before switching and available right after switching. – ShadSterling Feb 8 '17 at 19:18
-1

You can use . script.sh syntax as long as the script you wish to execute is in the current directory.

You can also prefix with the interpreter, like sh or bash. example: bash script.sh

  • 8
    . script.sh will break if script contains exit, has unexpected effects e.g. if it redefined PATH "temporarily"; it also only works for scripts for your current shell – sourcejedi Feb 6 '17 at 11:26
  • @sourcejedi Concerning exit you could put it in inside parentheses, i.e. a subshell, but true, it would still be only for scripts in the same shell. – phk Feb 6 '17 at 17:43
  • The question says “an executable file”. These won’t work for a binary executable; only for a script.  And your second paragraph duplicates Zanna’s answer. – Scott Feb 7 '17 at 7:00
  • Well, my bad, I mostly execute and dev bash stuff, so I assumed we were talking about bash scripts :) – UltimateByte Feb 7 '17 at 12:01
  • Not just only for a script, but only for a Bash script. – Oskar Skog Feb 9 '17 at 5:27

protected by Michael Mrozek Feb 9 '17 at 16:04

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?