how to get only version number of a program? pipe into grep - linux

rsync --version
gives lots of info but I just want to grab the first line
rsync version 3.1.1
How to do this? I tried to pipe into grep but I can't

There are lots of ways to slice this pie. If you want the whole first line, you can use any of these:
rsync --version | head -n 1
rsync --version | awk NR==1
rsync --version | sed -n 1p
rsync --version | grep '^rsync *version'
If you want just the version number without the rest of the line, that's not much harder, but it depends which part of the line you want. On my Mac, the version line reads rsync version 2.6.9 protocol version 29, and a naïve grab would likely yield the 29 - presumably not what you want. Either of the following will output just the 2.6.9 by itself:
rsync --version | awk 'NR==1 {print $3}'
rsync --version | sed -n '1s/^rsync *version \([0-9.]*\).*$/\1/p'

If you just need to get the first line of output use head command
rsync --version | head -1

Related

Loop to filter out lines from apache log files

I have several apache access files that I would like to clean up a bit before I analyze them. I am trying to use grep in the following way:
grep -v term_to_grep apache_access_log
I have several terms that I want to grep, so I am piping every grep action as follow:
grep -v term_to_grep_1 apache_access_log | grep -v term_to_grep_2 | grep -v term_to_grep_3 | grep -v term_to_grep_n > apache_access_log_cleaned
Until here my rudimentary script works as expected! But I have many apache access logs, and I don't want to do that for every file. I have started to write a bash script but so far I couldn't make it work. This is my try:
for logs in ./access_logs/*;
do
cat $logs | grep -v term_to_grep | grep -v term_to_grep_2 | grep -v term_to_grep_3 | grep -v term_to_grep_n > $logs_clean
done;
Could anyone point me out what I am doing wrong?
If you have a variable and you append _clean to its name, that's a new variable, and not the value of the old one with _clean appended. To fix that, use curly braces:
$ var=file.log
$ echo "<$var>"
<file.log>
$ echo "<$var_clean>"
<>
$ echo "<${var}_clean>"
<file.log_clean>
Without it, your pipeline tries to redirect to the empty string, which results in an error. Note that "$file"_clean would also work.
As for your pipeline, you could combine that into a single grep command:
grep -Ev 'term_to_grep|term_to_grep_2|term_to_grep_3|term_to_grep_n' "$logs" > "${logs}_clean"
No cat needed, only a single invocation of grep.
Or you could stick all your terms into a file:
$ cat excludes
term_to_grep_1
term_to_grep_2
term_to_grep_3
term_to_grep_n
and then use the -f option:
grep -vf excludes "$logs" > "${logs}_clean"
If your terms are strings and not regular expressions, you might be able to speed this up by using -F ("fixed strings"):
grep -vFf excludes "$logs" > "${logs}_clean"
I think GNU grep checks that for you on its own, though.
You are looping over several files, but in your loop you constantly overwrite your result file, so it will only contain the last result from the last file.
You don't need a loop, use this instead:
egrep -v 'term_to_grep|term_to_grep_2|term_to_grep_3' ./access_logs/* > "$logs_clean"
Note, it is always helpful to start a Bash script with set -eEuCo pipefail. This catches most common errors -- it would have stopped with an error when you tried to clobber the $logs_clean file.

Can I pipe lshw warnings to /dev/null when I run it as a standard user?

I'm trying to create an alias for getting memory on my machine, currently I have alias mem="lshw | grep size | awk -F: '{print $2}'", and when I run it as a non-super user, I get the following warning message:
WARNING: you should run this program as super-user.
WARNING: output may be incomplete or inaccurate, you should run this program as super-user.
size: 23GiB
I'm not worried about the results being potentially incomplete, in fact when I diff the output when running as root vs a standard user, it's exactly the same. Does anybody know how to get rid of these warnings? I tried piping stderr to /dev/null, but that didn't work. Does anyone else know how to get rid of these warnings?
Can I interest you in
alias mem='free -g | grep Mem | awk '\''{print $2 " GiB"}'\'
free -m will give MiB; you can change the " GiB" part to whatever you want (or remove it).
I don't have lshw installed on my machine, so I can't help you debug your version, unfortunately.
alias mem="lshw 2> /dev/null| grep size | awk -F: '{print $2}'"
Alternatively you can use free or read from /proc/meminfo
cat /proc/meminfo |grep MemTotal
I'm not sure how you piped to dev/null, but this works for me:
lshw 2> /dev/null | grep size | awk -F: '{print $2}'
Ignoring that there are other tools more suited to getting the memory, if there is something you need and lshw is your only option, you would be better suited to use -json or -xml output and use a tool to parse it like jq or xmllint. The version of lshw on my distro outputs invalid json that can't be parsed, but does have valid xml output.
This would accomplish your goal, although the path may very well be different for you:
lshw -xml 2> /dev/null | xmllint --xpath '/list/node/node/node[#id="memory"]/size/text()' -
Or add a one grep:
... | grep "size:"

How to parse the correct version number?

The command below will return the corresponding strings
$ docker-compose exec postgres postgres --version
postgres (PostgreSQL) 10.4 (Debian 10.4-2.pgdg90+1)
I am trying to get the postgresql version but when I tried, the Debian version and other numbers are included like
$ pg_version=$(docker-compose exec postgres postgres --version | sed 's/[^0-9.]//g')
10.410.42.901
I am wondering how to get the 10.4 only
awk -v RS=" " '/^[0-9.]+$/{print; exit}'
grep -oE '[.0-9]+' | head -1
tr ' ' '\n' | grep -oE -m 1 '[.0-9]+'
sed 's|^[^0-9.]*\([0-9.]\+\).*|\1|'
Modify the sed as followed would help,
sed -E 's/.*PostgreSQL[^0-9.]+([0-9.]*).*/\1/'
\1 would only match to the version number right behind "PostgreSQL".
pg_version=$(docker-compose exec postgres postgres -V | grep -oE '[.0-9]+' | head -1)
You could use grep with something like this:
$ grep -oP "PostgreSQL.\s\K.+?(?=\s)"
For example:
$ echo "postgres (PostgreSQL) 10.4 (Debian 10.4-2.pgdg90+1)" | grep -oP "SQL.\s\K.+?(?=\s)"
10.4
The \K can be read as excluding everything to the left *SQL)<space> before it and return only the right part .+?(?=\s) until and space \s is found.

How to isolate part of a line of text in order to use it as a variable

I'm creating bash script and want to check version number of program from a line in a file and use it to make different checks and operations.
The version line in file is looking like this (examples):
Program Version 1.3
or
Program Version 1.3.1
It's on different lines in different versions but always follow the same syntax. How to remove the first part and isolate only the version number in order to put it in a variable?
Using GNU grep with -P for perl-style regEx match, and -o flag to return only the matching pattern.
grep -oP 'Program Version \K[^ ]*' file
1.3.1
To save it in a variable
versionNo="$(grep -oP 'Program Version \K[^ ]*' file)"
printf "%s\n" "$versionNo"
1.3.1
Use perl regEx itself,
perl -lne 'print "$1" if /^Program Version (\d.+)/' file
1.3.1
in variable,
versionNo="$(perl -lne 'print "$1" if /^Program Version (\d.+)/' file)" file
printf "%s\n" "$versionNo"
1.3.1
Using GNU sed
sed -r 's/Program Version ([[:digit:]].+).*/\1/' file
1.3.1
and
versionNo="$(sed -r 's/Program Version ([[:digit:]].+).*/\1/' file)" file
printf "%s\n" "$versionNo"
1.3.1
I guess you obtain that Program Version 1.3.1 for example launching some kind of command. Well, try this:
#!/bin/bash
version=$(yourCommandWhichShowsVersion 2> /dev/null | egrep "^Program Version [0-9]" | awk '{print $3}')
Explanation:
You need to launch the command which show the version
You redirect the output to egrep which search through all lines matching only which starts ^ <- this is to start string, with the desired text Program Version, and this [0-9] is to match one number. If you don't know if the version can be 1.3 or 1.3.1 or 1 that's all you need.
awk is going to "select" the second column (first is "Program version" and second is the version number)
Good luck!
Value=$(cat program.txt | grep Program\ Version\ | sed "s/Program \Version\ //g")
Just finds Program Version then strip it out with sed.
Edit: Sorry misread. Removed version number
I would just use grep and cut for this, since the pattern is fixed:
# find the first occurrence of the line (-m 1) starting with the pattern (^) and
# the third field (cut -f3) is the version
# this makes sure we ignore
# a) multiple occurrences of the pattern, if any
# b) occurrence of "Program Version" anywhere else on a line
# we make no assumption about the format of the version number
version=$(grep -m 1 "^Program Version " program.txt | cut -f3 -d' ')
if [[ -z $version ]]; then
# version not specified
# your exception handler here
fi
Some possible solutions for the problem:
awk awk '/Program Version/{print $3}' file.txt
grep grep -oP "Program Version \K[^ ]*" file.txt
sed sed -n '/Program Version /s///p' file.txt
perl perl -lane 'if (/Program Version/) {print $F[2]}' file.txt
(HTH) Hope This Helps.
Here is what I have used at the end:
Version=`find . -type f -name "filename" -exec grep -h 'Program Version' {} + | awk -F " " '{print $3}'`
I have used find + grep to receive the line with the version that I need and -f in awk to define field separator to be blank space and with that I have separated the version number from the rest of the results. Thank you all for your answers.

How to return substring from a linux command

I'm connecting to an exadata and want to get information about "ORACLE_HOME" variable inside them. So i'm using this command:
ls -l /proc/<pid>/cwd
this is the output:
2 oracle oinstall 0 Jan 23 21:20 /proc/<pid>/cwd -> /u01/app/database/11.2.0/dbs/
i need the get the last part :
/u01/app/database/11.2.0 (i dont want the "/dbs/" there)
i will be using this command several times in different machines. So how can i get this substring from whole output?
Awk and grep are good for these types of issues.
New:
ls -l /proc/<pid>/cwd | awk '{print ($NF) }' | sed 's#/dbs/##'
Old:
ls -l /proc/<pid>/cwd | awk '{print ($NF) }' | egrep -o '^.+[.0-9]'
Awk prints the last column of the input which is your ls command and then grep grabs the beginning of that string up the last occurrence of numbers and dots. This is a situational solution and perhaps not the best.
Parsing the output of ls is generally considered sub-optimal. I would use something more like this instead:
dirname $(readlink -f /proc/<pid>/cwd)

Resources