Formatting numbers to fixed width - bash

I have this output:
30.1.2003
3.3.2003
25.12.2003
I want to make print each value except the year in two digits (might have leading values). i.e
30.01.2003
03.03.2003
25.12.2003

You can use printf:
echo 30.1.2003 | tr . ' ' | xargs printf '%02d.%02d.%04d\n'

awk -F. -v OFS="." '{for(i=1;i<=NF;i++)$i=(length($i)<2?"0":"")$i}7' file
if your output was from some process, do :
yourApp|awk -F. -v OFS="." '{for(i=1;i<=NF;i++)$i=(length($i)<2?"0":"")$i}7'

Related

Adjusting column padding in bash

Any idea how can I put the output as the following?
Input:
1 GATTT
2 ATCGT
Desired output:
1 GATTT
2 ATCGT
I tried the following and it did not work
cut -c7,1-6,8-
$ awk -v OFS='\t' '{print $1,$2}' input
1 GATTT
2 ATCGT
or
$ awk '{print $1 "\t" $2}' input
SED can also be used:
sed "s/[:digit:]* .*/ &/g" input
1 GATTT
2 ATCGT
I'm assuming that the original whitespace were 6 spaces based on your cut command. The easiest way to knock this out with simple bash commands is using a tab for separation on the output.
echo " 1 GATTT" | cut -d ' ' -f 7- | tr ' ' '\t'
The cut command makes the delimeter a space character and takes from field 7 on. Then the tr (translate) command converts the remaining space to a tab.

Count number of Special Character in Unix Shell

I have a delimited file that is separated by octal \036 or Hexadecimal value 1e.
I need to count the number of delimiters on each line using a bash shell script.
I was trying to use awk, not sure if this is the best way.
Sample Input (| is a representation of \036)
Example|Running|123|
Expected output:
3
awk -F'|' '{print NF-1}' file
Change | to whatever separator you like. If your file can have empty lines then you need to tweak it to:
awk -F'|' '{print (NF ? NF-1 : 0)}' file
You can try
awk '{print gsub(/\|/,"")}'
Simply try
awk -F"|" '{print substr($3,length($3))}' OFS="|" Input_file
Explanation: Making field separator -F as | and then printing the 3rd column by doing $3 only as per your need. Then setting OFS(output field separator) to |. Finally mentioning Input_file name here.
This will work as far as I know
echo "Example|Running|123|" | tr -cd '|' | wc -c
Output
3
This should work for you:
awk -F '\036' '{print NF-1}' file
3
-F '\036' sets input field delimiter as octal value 036
Awk may not be the best tool for this. Gnu grep has a cool -o option that prints each matching pattern on a separate line. You can then count how many matching lines are generated for each input line, and that's the count of your delimiters. E.g. (where ^^ in the file is actually hex 1e)
$ cat -v i
a^^b^^c
d^^e^^f^^g
$ grep -n -o $'\x1e' i | uniq -c
2 1:
3 2:
if you remove the uniq -c you can see how it's working. You'll get "1" printed twice because there are two matching patterns on the first line. Or try it with some regular ascii characters and it becomes clearer what the -o and -n options are doing.
If you want to print the line number followed by the field count for that line, I'd do something like:
$grep -n -o $'\x1e' i | tr -d ':' | uniq -c | awk '{print $2 " " $1}'
1 2
2 3
This assumes that every line in the file contains at least one delimiter. If that's not the case, here's another approach that's probably faster too:
$ tr -d -c $'\x1e\n' < i | awk '{print length}'
2
3
0
0
0
This uses tr to delete (-d) all characters that are not (-c) 1e or \n. It then pipes that stream of data to awk which just counts how many characters are left on each line. If you want the line number, add " | cat -n" to the end.

Separate columns in one line using Bash script

I am using bash scripting in Linux. I have a variable that looks like this:
a="1-1-1 1-1-2 1-1-3 1-1-4"
I want to separate columns with values equal to or greater than 1-1-3 using AWK.
My output should be:
1-1-3 1-1-4
Can someone help me with this?
You can do it without a loop, if you use the space as record separator:
echo $a | awk -v RS=' ' -v ORS=' ' '{$1=$1} $1>="1-1-3"'
You can loop over the line and compare:
echo $a | awk -v ORS=' ' '{for(i=1;i<=NF;i++) if($i >= "1-1-3") print $i;}'
sort's -V option gives you "version" sorting that might be helpful:
$ a="2-0-0 1-1-1 1-1-2 1-1-3 1-1-4"
$ tr ' ' '\n' <<<"$a" | sort -V
1-1-1
1-1-2
1-1-3
1-1-4
2-0-0

Repeatly replace a delimiter at a given count (4), with another character

Given this line:
12,34,56,47,56,34,56,78,90,12,12,34,45
If the count of the commas(,) is greater than four, replace 4th comma(,) with ||.
If the count is lesser or equal to 4 no need replace the comma(,).
I am able to find the count by the following awk:
awk -F\, '{print NF-1}' text.txt
then I used an if condition to check if the result is greater than 4. But unable to replace 4th comma with ||
Find the count of the delimiter in a line and replace the particular position with another character.
Update:
I want to replace comma with || symbol after every 4th occurrence of the comma. Sorry for the confusion.
Expected output:
12,34,56,47||56,34,56,78||90,12,12,34||45
With GNU awk for gensub():
$ echo '12,34,56,47,56,34' | awk -F, 'NF>5{$0=gensub(/,/,"||",4)}1'
12,34,56,47||56,34
$ echo '12,34,56,47,56' | awk -F, 'NF>5{$0=gensub(/,/,"||",4)}1'
12,34,56,47,56
$ echo 12,34,56,47,56,34,56,78,90,12,12,34,45 | sed 's/,/||/4'
12,34,56,47||56,34,56,78,90,12,12,34,45
$ echo 12,34,56,47 | sed 's/,/||/4'
12,34,56,47
Should work with any POSIX sed
Update:
For the updated question you can use
$ echo 12,34,56,47,56,34,56,78,90,12,12,34,45 | sed -e 's/\(\([^,]*,\)\{3\}[^,]*\),/\1||/g'
12,34,56,47||56,34,56,78||90,12,12,34||45
Unfortunately, POSIX sed's s command can take either a number or g as a flag, but not both. GNU sed allows the combination, but it does not do what we want in this case. So you have to spell it out in the regular expression.
Using awk you can do:
s='12,34,56,47,56,34,56,78,90,12,12,34,45'
awk -F, '{for (i=1; i<NF; i++) printf "%s%s", $i, (i%4?FS:"||"); print $i}' <<< "$s"
12,34,56,47||56,34,56,78||90,12,12,34||45
if the count is greater than four i want to replace 4th comma(,) with
||
give this line a try (gnu sed):
sed -r '/([^,]*,){4}.*,/s/,/||/4' file
test:
kent$ echo ",,,,,"|sed -r '/([^,]*,){4}.*,/s/,/||/4'
,,,||,
kent$ echo ",,,,"|sed -r '/([^,]*,){4}.*,/s/,/||/4'
,,,,
kent$ echo ",,,"|sed -r '/([^,]*,){4}.*,/s/,/||/4'
,,,
with awk
awk -F, 'NF-1>4{for(i=1;i<NF;i++){if(i==4)k=k$i"||";else k=k$i","} print k$NF}' filename

Get the part of string after the delimiter

The string format is
Executed: variable_name
What is the simplest way to get the *variable_name* sub-string?
foo="Executed: variable_name"
echo ${foo##* } # Strip everything up to and including the rightmost space.
or
set -- $foo
echo $2
Unlike other solutions using awk, sed, and whatnot, these don't fork other programs and save thousands of CPU cycles since they execute completely in your shell. They are also more portable (unlike ${i/* /} which is a bashism).
With sed:
echo "Executed: variable_name" | sed 's/[^:]*: //'
Using awk:
echo 'Executed: variable_name' | awk -F' *: *' '{print $2}'
variable_name
If you have the string in a variable:
$ i="Executed: variable_name"
$ echo ${i/* /}
variable_name
If you have the string as output of a command
$ cmd
Executed: variable_name
$ cmd | awk '{print $NF}'
variable_name
Note that 'NF' means "number of fields", so $NF is always the last field on the line. Fields are assumed to be separated by spaces (unless -F is specified)
If your variable_name could have spaces in it, the
-F' *: *'
mentioned previously ensures that only the ": " is used as a field separator. However, this will preserve spaces at the end of the line if there are any.
If the line is mixed in with other output, you might need to filter.
Either grep..
$ cmd | grep '^Executed: ' | awk '{print $NF}'
or more clever awk..
$ cmd | awk '/^Executed: /{print $NF}'

Resources