while [ -f /tmp/restarting_server ] ; do {
[ $((i=i+1)) -ge 10 ] && exit 1
sleep 1
} ; done
You dont need find
if you know already the exact filename, pathname, and conditions under which a file should be acceptably found.
So the other problem - exiting your script from your -exec
statement - is maybe not the problem you consider it to be. find
doesn't build in an option for kill
ing its parent shell because the shell already provides it.
find … -exec sh -c kill\ $$ \;
Consider also that you can use this construct for signalling based on existing paths even if you're not certain before hand where they'll be:
trap 'stuff to do' USR1
… #later…
find … -exec sh -c kill\ -USR1\ $$ \;
And this opens a lot of other options to you as well:
find … -exec sh -c exec…
EDIT:
I've just thought of other options involving parameter expansion
to make your shell exit without find
's -exec
at all that could be used in other ways:
hold_file="$(find . -name file)"
${hold_file:+false} : || exit 1
or
N= ; hold_file="$(find . -name file)"
${hold_file:+${N:?lock file remains, exiting...}}
Both of these will only cause an exit if the variable to which you assign find
's stdout
is neither null
or unset. And of course, should you desire to fail based on an empty find, you can do the same with :-
instead of :+
and omitting the $N
ull value variable entirely.
Or just to alter find
's exit status:
$(find . -name file -exec echo false \; ) : || exit 1
This is binfmt_misc in action: it allows the kernel to be told how to run binaries it doesn't know about. Look at the contents of /proc/sys/fs/binfmt_misc
; among the files you see there, one should explain how to run Mono binaries:
enabled
interpreter /usr/lib/binfmt-support/run-detectors
flags:
offset 0
magic 4d5a
(on a Debian system). This tells the kernel that binaries starting with MZ
(4d5a
) should be given to run-detectors
. The latter figures out whether to use Mono or Wine to run the binary.
Binary types can be added, removed, enabled and disabled at any time; see the documentation above for details (the semantics are surprising, the virtual filesystem used here doesn't behave entirely like a standard filesystem). /proc/sys/fs/binfmt_misc/status
gives the global status, and each binary "descriptor" shows its individual status. Another way of disabling binfmt_misc
is to unload its kernel module, if it's built as a module; this also means it's possible to blacklist it to avoid it entirely.
This feature allows new binary types to be supported, such as MZ executables (which include Windows PE and PE+ binaries, but also DOS and OS/2 binaries!), Java JAR files... It also allows known binary types to be supported on new architectures, typically using Qemu; thus, with the appropriate libraries, you can transparently run ARM Linux binaries on an Intel processor!
Your question stemmed from cross-compilation, albeit in the .NET sense, and that brings up a caveat with binfmt_misc
: some configuration scripts misbehave when you try to cross-compile on a system which can run the cross-compiled binaries. Typically, detecting cross-compilation involves building a binary and attempting to run it; if it runs, you're not cross-compiling, if it doesn't, you are (or your compiler's broken). autoconf
scripts can usually be fixed in this case by explicitly specifying the build and host architectures, but sometimes you'll have to disable binfmt_misc
temporarily...
Best Answer
Bash knows nothing about ELF. It simply sees that you asked it to run an external program, so it passes the name you gave it as-is to
execve(2)
. Knowledge of things like executable file formats, shebang lines, and execute permissions lives behind that syscall, in the kernel.(It is the same for other shells, though they may choose to use another function in the
exec(3)
family instead.)In Bash 4.3, this happens on line 5195 of
execute_cmd.c
in theshell_execve()
function.If you want to understand Linux at the source code level, I recommend downloading a copy of Research Unix V6 or V7, and going through that rather than all the complexity that is in the modern Linux systems. The Lions Book is a good guide to the code.
V7 is where the Bourne shell made its debut. Its entire C source code is just a bit over half the size of just that one C file in Bash. The Thompson shell in V6 is nearly half the size of the original Bourne shell. Yet, both of these simpler shells do the same sort of thing as Bash, and for the same reason. (It appears to be an
execv(2)
call fromtexec()
in the Thompson shell and anexecve()
call fromexecs()
in the Bourne shell'sservice.c
module.)