Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I think, what Sam wants to do may be not possible. </p> <p>To what degree a half-baken workaround is possible, depends on... </p> <ul> <li>...the default shell of users, and </li> <li>...which alternative shells they are allowed to use.</li> </ul> <p>If I understand Sam's requirement correctly, he wants to have a 'script', <code>myscript</code>, that is...</p> <ol> <li>...not <em>directly</em> executable via invoking it by its name <code>myscript</code> (i.e. that has <code>chmod a-x</code>);</li> <li>...not <em>indirectly</em> executable for users by invoking <code>sh myscript</code> or invoking <code>bash myscript</code></li> <li>...<strong><em>only</em></strong> running its contained functions and commands if invoked by sourcing it: <code>. myscript</code></li> </ol> <p>The first things to consider are these</p> <ol> <li>Invoking a script directly by its name (<code>myscript</code>) requires a first line in the script like <code>#!/bin/bash</code> or similar. This will directly determine which installed instance of the bash executable (or symlink) will be invoked to run the script's content. This will be a new shell process. It requires the scriptfile itself to have the executable flag set.</li> <li>Running a script by invoking a shell binary with the script's (path+)name as an argument (<code>sh myscript</code>), is the same as '1.' -- <strong><em>except that the executable flag does not need to be set, and said first line with the hashbang isn't required either</em></strong>. The only thing needed is that the invoking user needs <em>read</em> access to the scriptfile.</li> <li>Invoking a script by sourcing its filename (<code>. myscript</code>) is very much the same as '1.' -- <strong><em>exept that it isn't a new shell that is invoked. All the script's commands are executed in the current shell</em></strong>, using its environment (and also "polluting" its environment with any (new) variables it may set or change. (Usually this is a very dangerous thing to do: but here it could be used to execute <code>exit $RETURNVALUE</code> under certain conditions....)</li> </ol> <p><strong>For '1.':</strong><br> Easy to achieve: <code>chmod a-x myscript</code> will prevent <code>myscript</code> from being directly executable. But this will not fullfill requirements '2.' and '3.'.</p> <p><strong>For '2.' and '3.':</strong><br> Much harder to achieve. Invokations by <code>sh myscript</code> require <em>reading</em> privileges for the file. So an obvious way out would seem to <code>chmod a-r myscript</code>. However, this will also dis-allow '3.': you will not be able to source the script either.</p> <p>So what about writting the script in a way that uses a <em>Bashism</em>? A Bashism is a specific way to do something which other shells do not understand: using specific variables, commands etc. This could be used inside the script to discover this condition and "do something" about it (like "display warning.txt", "mailto admin" etc.). But there is no way in hell that this will prevent <code>sh</code> or <code>bash</code> or any other shell from reading and trying to execute all the following commands/lines written into the script unless you kill the shell by invoking <code>exit</code>.</p> <p><em>Examples:</em> in Bash, the environment seen by the script knows of <code>$BASH</code>, <code>$BASH_ARGV</code>, <code>$BASH_COMMAND</code>, <code>$BASH_SUBSHELL</code>, <code>BASH_EXECUTION_STRING</code>... . If invoked by <code>sh</code> (also if <em>sourced</em> inside a <code>sh</code>), the executing shell will see all these <code>$BASH_*</code> as empty environment variables. Again, this could be used inside the script to discover this condition and "do something"... <em>but not prevent the following commands from being invoked!</em></p> <p>I'm now assuming that...</p> <ol> <li>...the script is using <code>#!/bin/bash</code> as its first line, </li> <li>...users have set Bash as their shell and are invoking commands in the following table from Bash and it is their <em>login shell</em>,</li> <li>...<code>sh</code> is available and it is a symlink to <code>bash</code> or <code>dash</code>.</li> </ol> <p>This will mean the following invokations are possible, with the listed values for environment variables</p> <pre> vars+invok's | ./scriptname | sh scriptname | bash scriptname | . scriptname ---------------+--------------+---------------+-----------------+------------- $0 | ./scriptname | ./scriptname | ./scriptname | -bash $SHLVL | 2 | 1 | 2 | 1 $SHELLOPTS | braceexpand: | (empty) | braceexpand:.. | braceexpand: $BASH | /bin/bash | (empty) | /bin/bash | /bin/bash $BASH_ARGV | (empty) | (empty) | (empty) | scriptname $BASH_SUBSHELL | 0 | (empty) | 0 | 0 $SHELL | /bin/bash | /bin/bash | /bin/bash | /bin/bash $OPTARG | (empty) | (empty) | (emtpy) | (emtpy) </pre> <p>Now you could put a logic into your text script:</p> <ul> <li>If <code>$0</code> is not equal to <code>-bash</code>, then do an <code>exit $SOMERETURNVALUE</code>.</li> </ul> <p>In case the script was called via <code>sh myscript</code> or <code>bash myscript</code>, then it will exit the calling shell. In case it was run in the current shell, it will continue to run. (Warning: in case the script has any other <code>exit</code> statements, your current shell will be 'killed'...)</p> <p>So put into your non-executable <code>myscript.txt</code> near its beginning something like this may do something close to your goal:</p> <pre><code>echo BASH=$BASH test x${BASH} = x/bin/bash &amp;&amp; echo "$? : FINE.... You're using 'bash ...'" test x${BASH} = x/bin/bash || echo "$? : RATS !!! -- You're not using BASH and I will kick you out!" test x${BASH} = x/bin/bash || exit 42 test x"${0}" = x"-bash" &amp;&amp; echo "$? : FINE.... You've sourced me, and I'm your login shell." test x"${0}" = x"-bash" || echo "$? : RATS !!! -- You've not sourced me (or I'm not your bash login shell) and I will kick you out!" test x"${0}" = x"-bash" || exit 33 </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload