Example
./test.sh R19
echo "$1" > test.txt
cat test.txt | grep -o ^[A-Z] > model.txt
cat test.txt | grep -o [0-9] > num1.txt
cat test.txt | grep -o [0-9]$ > num2.txt
echo "$(cat model.txt)00$(cat num1.txt)00$(cat num2.txt)"
Im expecting to see R001009, however what i get is
R001
9009
So how can i get it so my num1.txt only recieves the middle number and not both?
That's because grep -o '[0-9]' is returning all the digits on separate lines.
The painful way would be cat test.txt | grep -o [0-9] | head -1 > num1.txt
But don't do that: you're doing way too much file I/O. Use a regex in bash:
if [[ $1 =~ ^([A-Z])([0-9])([0-9])$ ]]; then
printf "%s00%d00%d\n" "${BASH_REMATCH[#]:1}"
fi
Make sure you're using #!/bin/bash as your shebang line.
$ set -- R19
$ if [[ $1 =~ ^([A-Z])([0-9])([0-9])$ ]]; then
> printf "%s00%d00%d\n" "${BASH_REMATCH[#]:1}"
> fi
R001009
Related
I have some key value pair arguments. I need to print them as is.
Example.
echo $X
(a=b) (c=d) (e=f)
echo "$X" | sed -E 's/([a-zA-Z0-9_]*=[a-zA-Z0-9_]*)/match/1'
echo "$X" | sed -E 's/([a-zA-Z0-9_]*=[a-zA-Z0-9_]*)/\1/1'
echo "$X" | sed -E 's/([a-zA-Z0-9_]*=[a-zA-Z0-9_]*)/\1/2'
echo "$X" | sed -E 's/([a-zA-Z0-9_]*=[a-zA-Z0-9_]*)/\1/3'
Post the above expresion, I wanted to print matching groups one by one. using .* in pattern matching is greedy and is printing either first or last matching groups only. How can I print any matching group in this way.
Here is my expected output.
a=b
c=d
e=f
This grep one-liner will do:
grep -o '[^(]*=[^)]*'
example:
kent$ grep -o '[^(]*=[^)]*' <<<'(a=b) (c=d) (e=f)'
a=b
c=d
e=f
Replace ) ( with a newline and remove the remaining parentheses.
echo "$X" | sed 's/) (/\n/g;s/[()]//g'
To print the $nth line, you can pipe the output to
sed -n "$n p"
I'm trying to extract the timestamp from the end of a shell variable like this:
Input=AEXP_CSTONE_EU_prpbdp_sourcefile_yyyymmddhhmmss.txt
TimeStamp=`echo $Input | awk -F"_" '{print $6}'`
This works for this particular case, but the format of the string can change. For example, it could also be:
Input=AEXP_CSTONE_EU_prpbdp_sourcefile_prospects_yyyymmddhhmmss.txt
The variable will always end with yyyymmddhhmmss.txt. How can I extract the timestamp consistently?
Given:
$ echo $Input
AEXP_CSTONE_EU_prpbdp_sourcefile_prospects_20151116141111.txt
You can use sed:
$ echo $Input | sed -n 's|.*_\([0-9]\{14\}\)\.txt|\1|p'
20151116141111
Or nested grep:
$ echo $Input | grep -Eo '_[0-9]{14}\.txt' | grep -Eo '[0-9]{14}'
20151116141111
awk:
$ echo $Input | awk -F_ '{split($NF, a, "."); print a[1]}'
20151116141111
Perl
$ echo $Input | perl -ne 'print $1 if /_(\d{14})\.txt/'
20151116141111
cut and rev:
$ echo $Input | rev | cut -d'_' -f 1 | rev | cut -d'.' -f 1
20151116141111
Bash:
$ last=${Input##*_}
$ echo $last
20151116141111.txt
$ ts=${last%.*}
$ echo $ts
20151116141111
In summary, lots of ways...
If you don't want to loose the .txt part, even easier:
$ echo $Input | sed -n 's|.*_\([0-9]\{14\}\.txt\)|\1|p'
20151116141111.txt
$ echo $Input | grep -Eo '[0-9]{14}\.txt$'
20151116141111.txt
$ echo $Input | awk -F_ '{print $NF}'
20151116141111.txt
$ echo $Input | perl -ne 'print $1 if /_(\d{14}\.txt)/'
20151116141111.txt
$ echo $Input | rev | cut -d'_' -f 1 | rev
20151116141111.txt
$ last=${Input##*_}
$ echo $last
20151116141111.txt
You need to match the part that will not change then:
TimeStamp=$(echo $Input | perl -pe 's/.*(\d{14})\.txt/$1/')
You are extracting the 6th field separated by _, yet it seems you really want to extract the last field. You can do that with parameter expansion:
timestamp=${Input##*_}
timestamp=${timestamp%.txt}
See BashFAQ 100 for more on string manipulation in bash.
In awk, you'd use $NF to reference the last field, though awk is overkill for this.
From this content (in a file):
myspecificBhost.fqdn.com myspecificaBhost.fqdn.com myspecificzBhost.fqdn.com
I need to print the next 4 characters from the "B":
Bhost
I tried:
echo ${var:position1:lenght}
but position 1 is never equal
Using BASH regex:
s='myspecificBhost.fqdn.com myspecificaBhost.fqdn.com myspecificzBhost.fqdn.com'
[[ "$s" =~ (B[a-z][a-z][a-z][a-z]) ]] && echo "${BASH_REMATCH[1]}"
Bhost
try sed command:
sed -nr '/.*c(.{4,6}).*/s//\1/p' input.txt | cut -c2-6
RESULT:
Bhost
With grep command:
cat input.txt | grep -o B.... | head -1
RESULT:
Bhost
Try with:
cat file | grep -o B....
Bash using parameter substitution. Outputs the 4 characters
after the first 'B':
text='myspecificBhost.fqdn.com myspecificaBhost.fqdn.com myspecificzBhost.fqdn.com'
text=${text#*B}
text=${text:0:4}
echo "${text}"
Output:
host
To get the leading 'B' use
echo "B${text}"
I am try to match only the digits from a text file that is in this format:
> 1234
I'm running thru the file with a loop. Every line store in $i
$i | grep "\d{4}"
Output looks like this:
>
1234
>
5678
Why is it still outputing the >? I want to remove those.
From man grep
-o, --only-matching
Print only the matched (non-empty) parts of a matching line, with each such part on a
separate output line.
Try grep -o ....
Test:
i="> 1234"
$ echo "$i"
> 1234
$ echo "$i" | grep -oP "\d{4}"
1234
I want to get a count of symbols in a file.
wc -c f1.txt | grep [0-9]
But this code return a line where grep found numbers. I want to retrun only 38. How?
You can use awk:
wc -c f1.txt | awk '{print $1}'
OR using grep -o:
wc -c f1.txt | grep -o "[0-9]\+"
OR using bash regex capabilities:
re="^ *([0-9]+)" && [[ "$(wc -c f1.txt)" =~ $re ]] && echo "${BASH_REMATCH[1]}"
pass data to wc from stdin instead of a file: nchars=$(wc -c < f1.txt)