List bash "bind -x" bindings - linux

I searched man bash, but couldn't find anything that lists out all current bind -x key bindings. Is there any way I could do that? I tried the following:
$ bind -x '"\C-`":"echo hello"'
# test binding: press CTRL+`
hello
# Binding works!
$ bind -p | grep 'hello'
# no output
$ bind -S
# no output
So, is there any way I could see a list of all bind -x currently active?

Seems like you can use bind -X (new in Bash 4.3):
$ help bind
...
-x keyseq:shell-command Cause SHELL-COMMAND to be executed when
KEYSEQ is entered.
-X List key sequences bound with -x and
associated commands in a form that can be
reused as input.
...
$

The above answer returned empty output on bash 4.3.48 for me. But capital ā€˜Pā€™ does work:
bind - display all function names (and bindings)
This will only give you bindings to functions:
bind -P
Explanation
-P List current readline function names and bindings.
-p Display readline function names and bindings in such a
way that they can be re-read.
Sample output
set-mark can be found on "\C-#", "\e ".
shell-expand-line can be found on "\e\C-e".
start-kbd-macro can be found on "\C-x(".
tilde-expand can be found on "\e&".
transpose-chars can be found on "\C-t".
transpose-words can be found on "\et".
undo can be found on "\C-x\C-u", "\C-_".
unix-line-discard can be found on "\C-u".
unix-word-rubout can be found on "\C-w".
upcase-word can be found on "\eu".
yank can be found on "\C-y".
yank-last-arg can be found on "\e.", "\e_".
yank-nth-arg can be found on "\e\C-y".
yank-pop can be found on "\ey".
bind - display all string insertions
This will give you bindings for arbitrary keystrokes:
bind -S
-S List key sequences that invoke macros and their values
-s List key sequences that invoke macros and their values
in a form that can be reused as input.
sample output:
\el outputs ls -lrtha --color=always\C-j
\ep outputs pwd\C-j
\er outputs docker rm
\ew outputs wget --no-check-certificate \"\"\e[D
manpage
Since it's surprisingly difficult to find the manpage for it, here it is:
bind [-m keymap] [-lpsvPSVX]
bind [-m keymap] [-q function] [-u function] [-r keyseq]
bind [-m keymap] -f filename
bind [-m keymap] -x keyseq:shell-command
bind [-m keymap] keyseq:function-name
bind readline-command
Display current readline key and function bindings, bind a key
sequence to a readline function or macro, or set a readline
variable. Each non-option argument is a command as it would
appear in .inputrc, but each binding or command must be passed
as a separate argument; e.g., '"\C-x\C-r": re-read-init-file'.
Options, if supplied, have the following meanings:
-m keymap
Use keymap as the keymap to be affected by the subsequent
bindings. Acceptable keymap names are emacs,
emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move,
vi-command, and vi-insert. vi is equivalent to
vi-command; emacs is equivalent to emacs-standard.
-l List the names of all readline functions.
-p Display readline function names and bindings in such a
way that they can be re-read.
-P List current readline function names and bindings.
-s Display readline key sequences bound to macros and the
strings they output in such a way that they can be re-
read.
-S Display readline key sequences bound to macros and the
strings they output.
-v Display readline variable names and values in such a way
that they can be re-read.
-V List current readline variable names and values.
-f filename
Read key bindings from filename.
-q function
Query about which keys invoke the named function.
-u function
Unbind all keys bound to the named function.
-r keyseq
Remove any current binding for keyseq.
-x keyseq:shell-command
Cause shell-command to be executed whenever keyseq is
entered. When shell-command is executed, the shell sets
the READLINE_LINE variable to the contents of the
readline line buffer and the READLINE_POINT variable to
the current location of the insertion point. If the
executed command changes the value of READLINE_LINE or
READLINE_POINT, those new values will be reflected in the
editing state.
-X List all key sequences bound to shell commands and the
associated commands in a format that can be reused as
input.
The return value is 0 unless an unrecognized option is given or
an error occurred.

Related

Bashscript throws command error when populating variable [duplicate]

This question already has answers here:
How do I set a variable to the output of a command in Bash?
(15 answers)
Bash variable from command with pipes, quotes, etc
(2 answers)
Variable variable assignment error -"command not found"
(1 answer)
Closed 1 year ago.
i have the following two lines in a batch script
iperf_options=" -O 10 -V -i 10 --get-server-output -P " $streams
$iperf_options=$iperf_options $proto
and
$streams = 2
$proto = -u
but when i run this i get the following error.
./bandwidth: line 116: -O: command not found
I am simply trying to wrote a string and then append it to a variable so why does it throw the error on the -O?
I have looked about the web but i jsut seem to find stuff about spaces around the "="
any help greatfully recived.
Thankyou
code block to show error
proto=-u
streams=2
iperf_options=" -O 10 -V -i 10 --get-server-output -P " $streams
$iperf_options=$iperf_options $proto
running this will give this out put
./test
./test: line 3: 2: command not found
./test: line 4: =: command not found
There are two main mistakes here, in a variety of combinations.
Use $ to get the value of a variable, never when setting the variable (or changing its properties):
$var=value # Bad
var=value # Good
var=$othervar # Also good
Spaces are critical delimiters in shell syntax; adding (or removing) them can change the meaning of a command in unexpected ways:
var = value # Runs `var` as a command, passing "=" and "value" as arguments
var=val1 val2 # Runs `val2` as a command, with var=val1 set in its environment
var="val1 val2" # Sets `var1` to `val1 val2`
So, in this command:
iperf_options=" -O 10 -V -i 10 --get-server-output -P " $streams
The space between iperf_options="..." and $streams means that it'll expand $streams and try to run it as a command (with iperf_options set in its environment). You want something like:
iperf_options=" -O 10 -V -i 10 --get-server-output -P $streams"
Here, since $streams is part of the double-quoted string, it'll be expanded (variable expand inside double-quotes, but not in single-quoted), and its value included in the value assigned to iperf_options.
There's actually a third mistake (or at least dubious scripting practice): building lists of options as simple string variables. This works in simple cases, but fails when things get complex. If you're using a shell that supports arrays (e.g. bash, ksh, zsh, etc, but not dash), it's better to use those instead, and store each option/argument as a separate array element, and then expand the array with "${arrayname[#]}" to get all of the elements out intact (yes, all those quotes, braces, brackets, etc are actually needed).
proto="-u" # If this'll always have exactly one value, plain string is ok
streams=2 # Same here
iperf_options=(-O 10 -V -i 10 --get-server-output -P "$streams")
iperf_options=("${iperf_options[#]}" "$proto")
# ...
iperf "${iperf_options[#]}"
Finally, I recommend shellcheck.net to sanity-check your scripts for common mistakes. A warning, though: it won't catch all errors, since it doesn't know your intent. For instance, if it sees var=val1 val2 it'll assume you meant to run val2 as a command and won't flag it as a mistake.

Bash: pipe command output to function as the second argument

In my bash script I have a function for appending messages to the log file. It is used as follows:
addLogEntry (debug|info|warning|error) message
It produces nicely formatted lines with severity indication, timestamp and calling function name.
I've been looking for a way to pass output of some standard commands like rm to this function, while still being able to specify severity as the first argument. I'd also like to capture both stdout and stderr.
Is this possible without using a variable? It just feels excessive to involve variables to record a measly log message, and it encumbers the code too.
You have two choices:
You can add support to your addLogEntry function to have it accept the message from standard input (when no message argument is given or when - is given as the message).
You can use Command Substitution to run the command and capture its output as an argument to your function:
addLogEntry info "$(rm -v .... 2>&1)"
Note that this will lose any trailing newlines in the output however (in case that matters).
You can also use xargs to accomplish this
$ rm -v ... 2>&1 | xargs -I% addLogEntry info %
info removed 'blah1'
info removed 'blah2'
...
In the case of this command, the addLogEntry is called for every line in the input.

'less' the file specified by the output of 'which'

command 'which' shows the link to a command.
command 'less' open the file.
How can I 'less' the file as the output of 'which'?
I don't want to use two commands like below to do it.
=>which script
/file/to/script/fiel
=>less /file/to/script/fiel
This is a use case for command substitution:
less -- "$(which commandname)"
That said, if your shell is bash, consider using type -P instead, which (unlike the external command which) is built into the shell:
less -- "$(type -P commandname)"
Note the quotes: These are important for reliable operation. Without them, the command may not work correctly if the filename contains characters inside IFS (by default, whitespace) or can be evaluated as a glob expression.
The double dashes are likewise there for correctness: Any argument after them is treated as positional (as per POSIX Utility Syntax Guidelines), so even if a filename starting with a dash were to be returned (however unlikely this may be), it ensures that less treats that as a filename rather than as the beginning of a sequence of options or flags.
You may also wish to consider honoring the user's pager selection via the environment variable $PAGER, and using type without -P to look for aliases, shell functions and builtins:
cmdsource() {
local sourcefile
if sourcefile="$(type -P -- "$1")"; then
"${PAGER:-less}" -- "$sourcefile"
else
echo "Unable to find source for $1" >&2
echo "...checking for a shell builtin:" >&2
type -- "$1"
fi
}
This defines a function you can run:
cmdsource commandname
You should be able to just pipe it over, try this:
which script | less

Nagios XI: Provide Multiple Arguments to a Command

I have created a custom plugin in order to monitor a parameter using Nagios XI. To execute that plugin remotely I must use:
/usr/local/nagios/libexec/check_nrpe -H [IP_ADDR] -c [PLUGIN_NAME] -a [ARGUMENT]
Having made appropriate changes in nrpe.cfg and /etc/sudoers, I could get correct results.
But, I need to provide multiple arguments to the command. What should be the syntax I must use?
I would make it a comment if i though anyone could read it. In my command.cfg I had made this
# 'clear_printqueue' event handler command definition
define command{
command_name clear_printqueue
command_line $USER1$/check_nrpe -H $HOSTADDRESS$ -p 5666 -c clear_printqueue -a "/PrinterName:$ARG1$" "/ServiceState:$SERVICESTATE$" "/StateType:$SERVICESTATETYPE$" "/ServiceAttempt:$SERVICEATTEMPT$" "/MaxServiceAttempts:$MAXSERVICEATTEMPTS$"
}
I only have Nagios Core 3.4.4 but I hope this might help. My ini file on the client contained this
clear_printqueue = cscript.exe //T:30 //NoLogo scripts\\lib\\wrapper.vbs scripts\\nagiosClear-PrintQueue.vbs "$ARG1$" "$ARG2$" "$ARG3$" "$ARG4$" "$ARG5$"
$ARG#$ gets passed to the script where it runs. In short I just passed the quoted arguments with spaces in between.

Why doesn't bash history expansion work in functions?

When I'm programming, I'll find myself cycling through the same three shell commands, e.g:
vim myGraphic.cpp
g++ -lglut -lGLU myGraphic.cpp -o prettyPicture
./prettyPicture
In order to avoid hitting the uparrow key thrice every time, I put the following in my bashrc:
function cyc {
CYCLE=3
!-$CYCLE
}
When I use the 'cyc' function, however, I get the error
"bash: !-3: command not found".
This technique of history expansion works interactively with the shell, but it does not seem to work with function definitions. What is the explanation for this difference? How might I make a function equivalent to 'cyc' that works?
This question has been asked here: use "!" to execute commands with same parameter in a script but in brief you need to
set -o history
set -o histexpand
in your script to enable history expansion.
History expansion seems to be expanded immediately, whereas other commands inside the body of a function are deferred until the function is called. Try defining the function at a shell prompt. I get bash: !-$CYCLE: event not found immediately, before the function definition is complete.
I tried escaping the exclamation point, but this causes it to be treated literally once the function is called, instead of being processed as a history expansion.
One alternative is a combination of eval and fc:
function cyc {
CYCLE=3
eval $( fc -nl -$CYCLE -$CYCLE )
}
I'll forgo the usual warning about eval because you'll simply be re-executing a command you previously ran, so caution will apply however you accomplish this. The given fc command will print a range of commands from history (-n suppresses the line number), and using the same value for the beginning and end of the range limits the output to a single command.
One way. It extract last four lines of your history, taking into account that history will be included, from that extract the first one for same result that !-3 and use perl to remove either the history number and leading spaces before executing the instruction.
function cyc {
CYCLE=4
history | tail -"$CYCLE" | head -1 | perl -ne 's/\A\s*\d+\s*// && system( $_ )'
}

Resources