I'm trying to re-create something like fbrun or similar. Need to figure how to wait for input, then execute that input, then quit.
I've put together a couple of scripts for you, mainly to gain some experience with shell scripting features I've never used like trapped signals. Unless I misunderstood your requirements, they should mostly work for you. I say "mostly" because it doesn't inform you whether the command you entered was invalid or not; it just blindly tries to execute it, and if it doesn't work, then no big deal.
Personally, I would just use something like
x11/rofi.
x11/dmenu and
x11/dmenu2 are also good choices if you want something that doesn't require so many dependencies.
x11/bbrun is also possibly a good choice if you're in a Blackbox-like environment, though it seems a bit heavy in terms of dependencies. (
jb_fvwm2 mentioned bbrun locks up Xorg, so I can't recommend that one.) However, any of them are likely more secure than the scripts below so long as they don't just pass the input line to a shell directly.
What I mean is that the run script below allows arbitrary shell code to be executed.
Code:
seq -f '%010.0f' 1073741824 | while read i; do echo $i; done >| /tmp/foo
will happily write all 11 GiB/Gio (approximately 11.8 GB/Go) to
/tmp/foo). Any shell-based solution will almost certainly be just as much of a security risk. For this reason, I recommend keeping them somewhere inside your
$HOME and ensure their permissions are set to 0700 (-rwx------) as I did so that only you can read, write, and execute them, especially if your
$HOME has 0755 permissions (drwxr-xr-x) since that allows other users to read and execute files in your
$HOME. At the very least, it should not be installed globally in some place like
/usr/local/bin simply because if someone else can access your machine remotely, they can use this program maliciously.
Here's a script I called 'xrun', which acts as the "run box":
Code:
#!/bin/sh
# Adjust the path at the end if necessary.
xterm -fg black -bg white -geometry 25x1 -T Run -e ~/bin/run
The logic of the
run
script below works like this:
- Read a line of input as a command to execute.
- If the read fails, exit.
- If the line contains only spaces, blanks, etc.:
- If the
elif
line is uncommented (see the end of this post), exit.
- Otherwise, go to step 1.
- Otherwise execute the command.
And here's the corresponding
run
script (don't let the comments and whitespace fool you; it's only 17-18 lines of actual code, depending on whether you uncomment the
elif
line or not):
Code:
#!/bin/sh
# Start the process
#
# Once the shell has loaded and is executing, the kill
# command will send SIGUSR2, which will be trapped. The
# trap will allow this script (and the xterm used to invoke
# it) to exit while leaving the shell executing the
# specified command.
#
# Params:
# $1 PID of this script
# $2 Command to execute
start() {
trap 'exit 0' USR2
nohup sh -c "kill -USR2 $1; $2" > /dev/null 2>&1 &
wait
}
# Read input until EOF is received, an error occurs, or a
# non-empty string is read.
while true; do
read -r input
status="$?"
# Remove trailing backslashes
input="${input%%\\}"
# 'read' returns 0 on success, 1 on EOF, or another
# status if an error occurred or a trapped signal
# interrupted the read. This is true whether
# anything was read or not.
#
# If exit status of 'read' wasn't 0 or 1, stop
# trying to read input.
expr "${status}"x : '[01]x' >/dev/null || break
# Remove all spaces/blanks, tabs, carriage returns,
# etc., resulting in an empty string if the input
# contained only spaces.
_input="$(echo "${input}" | tr -d '[:space:]')"
# If the string wasn't empty, execute the command.
# If the string was empty and EOF was received, stop
# trying to read input. Otherwise, clear the screen
# to try again.
if [ -n "${_input}" ]; then start $$ "${input}"
elif [ x"${status}" = x1 ]; then break
# Uncomment the 'elif' line below to allow exiting
# with empty input
#elif true; then break
else tput up && tput ce
fi
done
return "${status}"
All I did was place them in
~/bin and
chmod 0700 ~/bin/run ~/bin/xrun
. If you want to allow exiting when you press Enter/Return with no input (or only spaces, tabs, etc. as input), then there's a
elif
condition you can uncomment near the end.
Edit: Also checked the syntax with
devel/hs-ShellCheck using
shellcheck -o all -s SHELL ~/bin/run
for all four shells supported by shellcheck and updated the run script accordingly. There are no more warnings now, and it even fixed a bug where backslashes would be ignored. This introduced a new problem with trailing slashes however, such as creating a file named
\ using
echo foo | tee foo \
. It doesn't make sense to allow trailing slashes since only one line of input is read, so they are removed. Single-quoting the backslash will do the trick if you need to use a trailing backslash (or just rearrange the command line if possible).