Bash. Parse error output without showing error - bash

I want to get and parse the python (python2) version. This way (which works):
python2 -V 2>&1 | sed 's/.* \([0-9]\).\([0-9]\).*/\1\2/'
For some reason, python2 is showing the version using the -V argument on its error output. Because this is doing nothing:
python2 -V | sed 's/.* \([0-9]\).\([0-9]\).*/\1\2/'
So it needs to be redirected 2>&1 to get parsed (stderr to stdout). Ok, but I'd like to avoid the error shown if a user launching this command has no python2 installed. The desired output on screen for a user who not have python2 installed is nothing. How can I do that? because I need the error output shown to parse the version.
I already did a solution doing before a conditional if statement using the hash command to know if the python2 command is present or not... so I have a working workaround which avoids the possibility of launching the python2 command if it is not present... but just curiosity. Forget about python2. Let's suppose is any other command which is redirecting stderr to stdout. Is there a possibility (bash trick) to parse its output without showing it if there is an error?
Any idea?

Print output only if the line starts with Python 2:
python2 -V 2>&1 | sed -n 's/^Python 2\.\([0-9]*\).*/2\1/p'
or,
command -v python2 >/dev/null && python2 -V 2>&1 | sed ...

Include the next line in your script
command python2 >/dev/null 2>&1 || {echo "python2 not installed or in PATH"; exit 1; }
EDITED: Changed which into command

Related

Is there a way for me to get specific words from an output of a command in bash?

For example, when running the dpkg command,
dpkg -s autofs
I would get an output like
dpkg-query: package 'autofs' is not installed and no information is available
But I just want to get the
not installed
part so that I can further use it for my script. Is there a command that can help me with it?
First of all, the words not installed are locale specific, so it will fail with anything but English locales. It is also non-predictable because it is not a published API Application Programming Interface.
So, even with some precautions, do not use this:
LC_MESSAGES=C dpkg-query --status autofs 2>&1 | grep -o 'not installed'
Check the return status of the dpkg-query command instead:
#!/usr/bin/env sh
package='autofs'
if dpkg-query --status "$package" >/dev/null 2>&1; then
printf 'Package %s is installed!\n' "$package"
else
printf 'Package %s is not installed!\n' "$package"
fi

Unable to capture command exit code in makefile

I'm trying to setup my first makefile and am hitting a block at step 1. In my shell script, I did this:
which brew | grep 'brew not found' >/dev/null 2>&1
if [ $? == 0 ]; then
xcode-select --install
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
fi
This worked just fine as a bash script. After some googling, for a Makefile, I've so far come up with this one command:
BREW_INSTALLED = $(shell which brew | grep 'brew not found' >/dev/null 2>&1; echo $$?)
However, running it gets me
make: BREW_INSTALLED: No such file or directory
I'm equally unsure when I should be adding # to a command (seems like anything I don't want to output?).
I'm currently on GNU Make 3.81.
There are several odds in this line:
BREW_INSTALLED = $(shell which brew | grep 'brew not found' >/dev/null 2>&1; echo $$?)
In case of success, which writes its output to stdout, in case of failure to stderr. You are trying to capture the error message on stdout.
To feed the stderr of which to grep, you would need to write
which brew 2>&1 >/dev/null | grep 'brew not found'
(The order of 2>&1 and > also matters).
But you should not rely on the specific error message of which.
But you already get the return code you want from which, so you don't need grep at all.
Which returns the number of failed arguments, or -1 when no `programname' was given.
https://linux.die.net/man/1/which
Consider using grep -q 'expression' to supress output instead of redirecting stdout and stderr.
-q, --quiet, --silent
Quiet; do not write anything to standard output. Exit immediately with zero status if any match is found, even if an error was detected.
https://linux.die.net/man/1/grep
And the error message you get has nothing to do with what I'm writing above. This means the shell is trying to run BREW_INSTALLED as command, which probably means that make puts it at the beginning of a new shell.
Maybe you wrote it after a tabspace? see https://www.gnu.org/software/make/manual/html_node/Recipe-Syntax.html
To capture the return code (as string!):
BREW_INSTALLED := $(shell which brew >/dev/null 2>&1; echo $$?)
A typical makefile would check the presence of needed tools like this:
BREW := $(shell which brew)
# Check if variable brew is empty
ifeq ($(BREW),)
$(error brew not found)
else
$(info brew found: $(BREW))
endif
all:
#echo "Do something with brew"
$(BREW) --version
Note: There must be no tabspaces in the first two indented lines.
The two Recipe lines if the all Rule have to be indented with tabs.
The # at the beginning of a recipe supresses echoing: https://www.gnu.org/software/make/manual/html_node/Echoing.html

macOS terminal bug "can't see typed characters" after execution ffmpeg coommand inside shell script

I execute from Terminal:
sh 1.sh
1.sh contents:
#!/bin/bash
S1=$(ffmpeg -i correct.wav -af silencedetect=noise=-50dB:d=0.1 -f null - 2>&1 | grep silence_duration -m 1 | awk '{print $NF}')
echo $S1
After execution I can't see any typed characters in macOS Terminal. Only invisible typing reset helps to solve the problem, but all previous output clears.
How can I modify the code to solve this bug? I guess the problem somewhere in 2>&1.
Bug screenshot if press enter several times after script execution:

Can bash -v output be redirected?

starting bash with -v option produces a long output to the console
$ bash -v
source ~/Dropbox/bin/tim_functions.sh
\#!/bin/bash
...several hundred more lines
I would like to capture the output to a file to make it easier to browse through, but I have tried bash -v 2>&1 > out_bash.txt and bash -v | tee out_bash.txt and cannot capture the information on the terminal screen within a file. It is as if the verbose output is neither stderr or stdout. How can this be?
Can anyone suggest a way to capture the output of bash -v ?
bash -v 2>&1 > out_bash.txt
is not what you want, it should be
bash -v >out_bash.txt 2>&1
I poked around and found this http://www.commandlinefu.com/commands/view/3310/run-a-bash-script-in-debug-mode-show-output-and-save-it-on-a-file
On the website they use
bash -x test.sh 2>&1 | tee out.test, but I tested it with
bash -v test.sh 2>&1 | tee out.test and it worked fine.
you can also use the exec command in the script to redirect all output:
#!/bin/bash
exec >> out.txt 2>> out.txt
set -x
set -v
echo "testing debug of shell scripts"
ls
After reading other helpful answers, I believe this issue has to do with how bash is sending the verbose information to tty--which is somehow different than stderr or stdout. It can be caught with the following work around:
$ screen -L
$ bash -v
$ exit #from the bash session
$ exit #from the screen session
This results in a screenlog.0 file being generated containing the output.
The bash -v output of interest was on a mac running 10.7.3 (Lion) with
$ bash --version
GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin11)
Copyright (C) 2007 Free Software Foundation, Inc.)
Another 10.6.8 mac I tried had a less (interesting/verbose) output, despite a similar .bashrc file.
You can use,
bash -v 2>&1 | tee file.txt
or
bash -v 2>&1 | grep search_string
Have you tried wrapping your child bash in a subshell?
( bash -v ) 2>&1 > out_bash.txt

bash command preserve color when piping [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Can colorized output be captured via shell redirect?
setup
In this case specifically I'm trying to preserve the colors in git status -s when piping it to another command.
Some git commands, diff for instance, and other commands like grep have an option --color=always but git status does not.
question
Is there a way to pipe or capture the output of a command and make it think it is outputting to the xterm shell so it doesn't automatically disable colors?
Here's a script snippet using the colorized output of ls as an example (on Mac OS X 10.6).
# no colored ls output if stdout is a pipe (and not a tty)
ls -G /
ls -G / | cat
script -q /dev/null ls -G / | tr -d '\r' | cat
# write output of script command to a variable
var="$(script -q /dev/null ls -G / | tr -d '\r' | cat)"
echo "$var"
Most commands that do print out those color codes explicitly check if stdout/stderr is a tty (using the isatty function).
If you want to preserve the color codes, you can run it within a terminal emulator like screen or the direct logger script, saving the output to a file.

Resources