5 ms·
You don't need to install anything; you could put this on the first line of your file, and achieve the same effect, with just tools you already have installed:
by lambda 12y ago
You don't need to install anything; you could put this on the first line of your file, and achieve the same effect, with just tools you already have installed:
//usr/bin/make -s "${0%.c}" && ./"${0%.c}" "$@"; s=$?; rm ./"${0%.c}"; exit $s
Actually, you could extend this to any file type that Make has built-in rules for, and which uses // as a comment delimiter:
//usr/bin/make -s "${0%.*}" && ./"${0%.*}" "$@"; s=$?; rm ./"${0%.*}"; exit $s
- htor 12y agoI applaud you. This must be the best hack I've seen so far.
- placeybordeaux 12y agoMake's intended purpose is to chain commands in a logical fashion. ;'s intended purpose is to separate lines to execute. How is this a hack?
- lambda 12y agoIt's a hack because it's relying on the fact that without a shebang line or the appropriate magic number for your executable format, most platforms interpret scripts as a shell script; and it's using the fact that // can be treated as a comment delimiter in C or as a redundant way of referring to / in shell. So we interpret the first line as a shell script which calls out to make, to build the input file, then execute it, then exit so we don't try interpreting the rest of the C source as shell; and that first line of shell is interpreted as a comment in C.
- placeybordeaux 12y agoApparently I had a reading comprehension failure. I thought he was just saying that you can use that as an alias instead of downloading a new command. That is neat.
- jimrandomh 12y agoI tried this out in my (wacky homebrew) shell, and it didn't work (ENOEXEC). Then I tried it in bash and it did. Turns out, this will only work when started with execvp, not when started with execv. All of the GNU adverbs I tried seem to get this right (nice, xargs, nohup), but I wouldn't be surprised to stumble across this issue later somewhere.
- lambda 12y agoYep, it's a hack that depends on execvp behavior. I'm pretty sure I've seen a case in which a particular script worked when called directly from Bash, but not when invoked by other things like xargs or nohup, because Bash actually will execute scripts under itself, while execvp will execute it under /bin/sh which is Dash on Debian/Ubuntu systems. In fact, it was even better than that; they had even used #!/bin/bash, but had whitespace before it, causing the shebang to just be treated as a comment and not the as an interpreter: https://stackoverflow.com/questions/24944405/why-is-the-following-bash-script-not-working-when-called-with-nohup https://stackoverflow.com/questions/24944405/why-is-the-foll... Looks like it's fairly standard for shells to have this behavior, and execvp() is intended to have the behavior of executing like a shell would, so searching the path to find the executable and then passing the result to the shell interpreter if the underlying execve() returns noexec. May be a feature to add to your wacky homebrew shell.
- jimrandomh 12y agoYou can make this do path-searching for make, rather than force it to be in /usr/bin, with //bin/true; make -s "${0%.c}" && ./"${0%.c}" "$@"; s=$?; rm ./"${0%.c}"; exit $s Which might matter for some platforms, since 'make' isn't usually something that gets the shebang treatment.
- lambda 12y agoI thought of that, and even tried it, but on Mac OS X it's in /usr/bin/true, while on my Debian system it's /bin/true, defeating the purpose of making this path independent. I considered a few no-ops, like /bin/cat (but that would then consume stdin) or /bin/echo -n, but there may be cases in which these can't be relied on either, so I figured that just keeping it simple but relying on the location of make was the better option.
- VanillaCafe 12y agoWhy not just /usr/bin/env make
- lambda 12y agoSure, you can do that. I didn't because it's (a) longer (and I was trying to do some minor golfing to keep it under 80 characters) and (b) doesn't have any stronger of a guarantee that it will be located in /usr/bin than make does. There's more than one way to do this. It's just a silly hack; I decided to keep it simpler as the other alternatives didn't seem strictly better.
- throwaway2048 12y agowell /usr/bin/env existing is a mandatory posix thing at least
- lambda 12y agoNope, there are systems in which it's in /bin/env, though you have to go fairly exotic before you find one that doesn't at least have a symlink in /usr/bin. I don't believe POSIX says anything about it http://www.in-ulm.de/~mascheck/various/shebang/#env http://www.in-ulm.de/~mascheck/various/shebang/#env In fact, POSIX doesn't even standardize the shebang at all; it is simply mentioned as a possible extension.
- ape4 12y agoThe // reminds me of JCL.
- ericfrederich 12y agoYeah... it is documented here http://rosettacode.org/wiki/Multiline_shebang#C http://rosettacode.org/wiki/Multiline_shebang#C
- lambda 12y agoThat's a lot less elegant than my version. Multiple lines? Using sed to filter out the extraneous lines? Hardcoding gcc rather than using the system CC via make? And it gets the arguments wrong, too.