history and cut command: get the second field - linux

I am trying to get the commands from the history command.
ubuntu#ip-172-31-13-192:~/redacted$ history
1 ls
2 sudo apt-get install git -y
3 git clone https://redacted#bitbucket.org/redacted/redacted.git
4 ls
5 cd redacted
ubuntu#ip-172-31-13-192:~/redacted$ history | cut -d ' ' -f 2
No output. What's wrong?

There are also spaces in the beginning of each row, so column 2 is most likely just another space. Since history's format is fixed, you could base your cut on the number of characters, like so:
[mureinik#computer /]$ history | cut -c8-

Through sed,
history | sed 's/^ *[^ ]* *//'
It removes all the leading spaces along with the numbers.

This is because cut gets a space as field separator, defining each one of them a different field.
So whenever you have history as this:
1 ls
2 sudo apt-get install git -y
3 git clone https://redacted#bitbucket.org/redacted/redacted.git
4 ls
5 cd redacted
^
what you get
When you do cut -d' ' -f2 you get the space just after each number.
How can you solve it?
squeeze the spaces with tr:
history | tr -s ' ' | cut -d' ' -f2
use awk to print the second field. For awk, many fields do not count, so that the following will always print the second block of text:
history | awk '{print $2}'

Related

How to extract the date time from a string using bash

I have the below strings and from those i need to extract the data and time. I were trying to get these using awk command i am unable to find our the solution. The below lined are the put put of
grep -ir 'can not save data' Aplication-aplicationName-server0046704* | awk -F' GMT' '{print$1}' | grep -v 'can not save data'
Aplication-aplicationName-server0046704.log.1:2020 May 27 10:23:16:147
Aplication-aplicationName-server0046704.log.bkp:2020 May 27 10:23:16:147
desired output :
2020 May 27 10:23:16:147
Using sed:
sed -E 's/^[^:]+://' | uniq
Explanation:
The sed command will remove everything before the first :
and the first :
The uniq command will remove every duplicate
Using cut:
cut -d ':' -f2- | uniq
Explanation:
cut will accept as delimeter a : (-d ':') and will print the fields
from the second to the end (-f2-)
The uniq command will remove every duplicate

Use of cut to display information from last command linux

I am trying to fetch the user name and IP from where they logged in on my system.
I used the following command:
last -i | grep 'Jan 12' | cut -f1,3
But I am getting full line as the result.
But when I use awk :
last -i | grep 'Jan 12' | awk '{print $1, $3}'
I am getting the correct result.
Why wrong output in case of cut command ?
Any help would be highly appreciated.
Default delimiter of cut is a tab, whereas default input field separator in awk is any whitespace i.e. space or tab.
To get the same behavior in cut, you need to add -d ' ' in cut to make it:
last -i | grep 'Jan 12' | tr -s ' ' | cut -d ' ' -f1,3
tr -s ' ' is required to squeeze multiple spaces into a single space.
However using awk lets you skip grep altogether and use:
last -i | awk '/Jan 12/{print $1, $3}'
In cut, default delimiter is [Tab]. Also with -d key you can specify only a single character as delimiter.
In last output there are 8 spaces in a row.
So, the best way is to use awk as in your example.
Bad, but working solution with cut:
last | grep 'Jun 23' | sed 's/\s\s*/ /g' | cut -d' ' -f1,3

Linux-About sorting shell output

I have output from a customised log file like this:
8 24 yum
8 24 yum
8 24 make
8 24 make
8 24 cd
8 24 cd
8 25 make
8 25 make
8 25 make
8 26 yum
8 26 yum
8 26 make
8 27 yum
8 27 install
8 28 ./linux
8 28 yum
I'd like to know if there's anyway to count the number of specific values of the third field. For example I may want to count the number of cd,yum and install only.
You can use awk to do get the third field values and wc -l to count the number.
awk '$3=="cd"||$3=="yum"||$3=="install"||$3=="cat" {print $0}' file | wc -l
You can also use egrep, but this will look for these words not only on the third field, but everywhere else in the line.
egrep "(cd|yum|install|cat)" file | wc -l
if you want to count a specific word on the third field, then you can do the above without multiple regexs.
awk '$3=="cd" {print $0}' | wc -l
A classic shell script to do the job is:
awk '{print $3}' "$file" | sort | uniq -c | sort -n
Extract values from column 3 with awk, sort the identical names together, count the repeats, sort the output in increasing order of count. The sort | uniq -c | sort -n part is a common meme.
If you're using GNU awk, you can do it all in the awk script; it might be more efficient, but for really humungous files, it can run out of memory where the pipeline doesn't (sort spills to disk when necessary; writing code to spill to disk in awk is not sensible).
Use cut, sort and uniq:
$ cut -d" " -f3 inputfile | sort | uniq -c
2 cd
1 install
1 ./linux
6 make
6 yum
For your input this
awk '{++a[$3]}END{for(i in a)print i "\t" a[i];}' file
Would print:
cd 2
install 1
./linux 1
make 6
yum 6
Using awk to count the occurrences of field three and sort to order the output:
$ awk '{a[$3]++}END{for(k in a)print a[k],k}' file | sort -n
1 install
1 ./linux
2 cd
6 make
6 yum
So filter by command:
$ awk '/cd|yum|install/{a[$3]++}END{for(k in a)print a[k],k}' file | sort -n
1 install
2 cd
6 yum
To stop partial matches such as grep in egrep use word boundaries \< and \> so the filter would be /\<cd\>|\<yum\>|\<install\>/
You can use grep to filter by multiple terms at the same time:
cut -f3 -d' ' file | grep -x -e yum -e make -e install | sort | uniq -c
Explanation:
The -x flag is to match only the lines that match exactly, as if with ^pattern$
The cut extracts the 3rd column only
We sort, uniq with count in the end for efficiency, after all junk is removed from the input
i guess u want to count the values of yum install & cd separately. if so, u shud go for 3 separate awk statements: awk '$3=="cd" {print $0}' file | wc -l
awk '$3=="yum" {print $0}' file | wc -l
awk '$3=="install" {print $0}' file | wc -l

Keep only second attribute from each line

I have a csv file with 4 attributes in each line, delimited by comma. I'm trying to come up with a sed command to keep only the second attribute from each line. Any ideas on how to do it?
You'd be better off with cut:
cut -d "," -f 2 file.txt
If you want to remove dupes, and you don't mind the order of the entries, simply do:
cut -d "," -f 2 file.txt | sort -u
And to extend to attrs 1 and to, simply use:
cut -d "," -f 1,2 file.txt | sort -u
You do not need sed for this . The fastest is with cut:
cut -d, -f2 file
However , if you want sed , you can do it so:
sed '/[^,]*,\([^,]*\).*/ sxx\1x' file

Script to replace tokens with values mentioned in properties file

I have a file values.properties which contain data, like:
$ABC=10
$XYZ=20
I want to create a shell script that will take each element one by one from above file.
Say $ABC, then go to file ABC.txt & replace the value of $ABC with 10.
Similarly, then go to file XYZ.txt and replace $XYZ with 20.
I think maybe this should be in the Unix and Linux section, the solution I've hacked together is as follows:
cat values.properties | grep "=" | cut -d "$" -f2 | awk -F "=" '{print "s/$"$1"/"$2"/g "$1".txt"}' | xargs -n2 sed -i
The flow is like so:
Filter out all the value assignments via: grep "="
Remove the '$' via: cut -d "$" -f2
Use awk to split the variable name and value and construct sed replacement command
Use xargs to pull in the replacement parameter and target file via: xargs -n2
Finally pass sed to as the command to xargs: xargs -n2 sed

Resources