Converting date format in bash - linux

I have similar different file of the format backup_2016-26-10_16-30-00 is it possible to rename using bash script to backup_26-10-2016_16:30:00 for all files.
Kindly suggest some method to fix this.
Original file:
backup_2016-30-10_12-00-00
Expected output:
backup_30-10-2016_12:00:00

To perform only the name transformation, you can use awk:
echo 'backup_2016-30-10_12-00-00' |
awk -F'[_-]' '{ print $1 "_" $3 "-" $4 "-" $2 "_" $5 ":" $6 ":" $7 }'
As fedorqui points out in a comment, awk's printf function may be tidier in this case:
echo 'backup_2016-30-10_12-00-00' |
awk -F'[_-]' '{ printf "%s_%s-%s-%s_%s:%s:%s\n", $1,$3,$4,$2,$5,$6,$7 }'
That said, your specific Linux distro may come with a rename tool that allows you to do the same while performing actual file renaming.

with perl based rename command:
$ touch backup_2016-30-10_12-00-00 backup_2016-26-10_16-30-00
$ rename -n 's/(\d{4})-([^_]+)_(\d+)-(\d+)-/$2-$1_$3:$4:/' backup*
rename(backup_2016-26-10_16-30-00, backup_26-10-2016_16:30:00)
rename(backup_2016-30-10_12-00-00, backup_30-10-2016_12:00:00)
remove the -n option for actual renaming

rename is for this task
$ rename 's/_(\d{4})-(\d\d-\d\d)_(\d\d)-(\d\d)-(\d\d)$/_$2-$1_$3:$4:$5/' backup_2016-30-10_12-00-00
but not sure will be simpler

you can also this script;
#!/bin/bash
fileName=$1
prefix=$(echo ${fileName} | cut -d _ -f1)
date=$(echo ${fileName} | cut -d _ -f2)
time=$(echo ${fileName} | cut -d _ -f3)
year=$(echo ${date} | cut -d - -f1)
day=$(echo ${date} | cut -d '-' -f2)
month=$(echo ${date} | cut -d '-' -f3)
formatedTime=$(echo $time | sed 's/-/:/g')
formatedDate=$day"-"$month"-"$year
formatedFileName=$prefix"_"$formatedDate"_"$formatedTime
echo $formatedFileName
Eg;
user#host:/tmp$ ./test.sh backup_2016-30-10_12-00-00
backup_30-10-2016_12:00:00

Related

Strip a part of string in linux

Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2 is my string and the result I want is vm-1.0.3
What is the best way to do this
Below is what I tried
$ echo Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2 | awk -F _ {'print $2'} | awk -F - {'print $1,$2'}
vm 1.0.3
I also tried
$ echo Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2 | awk -F _ {'print $2'} | awk -F - {'print $1"-",$2'}
vm- 1.0.3
Here I do not need space in between
I tried using cut and I got the expected result
$ echo Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2 | awk -F _ {'print $2'} | cut -c 1-8
vm-1.0.3
What is the best way to do the same?
Making assumptions from the 1 example you provided about what the general form of your input will be so it can handle that robustly, using any sed:
$ echo 'Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2' |
sed 's/^[^-]*-[^-]*-[^_]*_\(.*\)-[^-]*$/\1/'
vm-1.0.3
or any awk:
$ echo 'Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2' |
awk 'sub(/^[^-]+-[^-]+-[^_]+_/,"") && sub(/-[^-]+$/,"")'
vm-1.0.3
You don't need 2 calls to awk, but your syntax with the single quotes outside the curly's, including printing the hyphen:
echo Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2 |
awk -F_ '{print $2}' | awk -F- '{print $1 "-" $2}'
If your string has the same format, let the field separator be either - or _
echo Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2 | awk -F"[-_]" '{print $4 "-" $5}'
Or split the second field on - and print the first 2 parts
echo Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2 | awk -F_ '{
split($2,a,"-")
print a[1] "-" a[2]
}'
Or with gnu-awk a bit more specific match with a capture group:
echo Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2 |
awk 'match($0, /^Apps-[^_]*_(vm-[0-9]+\.[0-9]+\.[0-9]+)/, a) {print a[1]}'
Output
vm-1.0.3
This is the easiest I can think of:
echo "Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2" | cut -c 25-32
Obviously you need to be sure about the location of your characters. In top of that, you seem to be have two separators: '_' and '-', while both characters also are part of the name of your entry.
echo 'Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2' | sed -E 's/^.*_vm-([0-9]+).([0-9]+).([0-9]+)-.*/vm-\1.\2.\3/'

Awk: parse node names out of "40*r13n15:40*r10n61:40*r11n18:40*r09n15"

I have a linux script for selecting the node.
For example:
4
40*r13n15:40*r10n61:40*r11n18:40*r09n15
The correct result should be:
r13n15
r10n61
r11n18
r09n15
My linux script content is like:
hostNum=`bjobs -X -o "nexec_host" $1 | grep -v NEXEC`
hostSer=`bjobs -X -o "exec_host" $1 | grep -v EXEC`
echo $hostNum
echo $hostSer
for i in `seq 1 $hostNum`
do
echo $hostSer | awk -F ':' '{print '$i'}' | awk -F '*' '{print $2}'
done
But unlucky, I got nothing about node information.
I have tried:
echo $hostSer | awk -F ':' '{print "'$i'"}' | awk -F '*' '{print $2}'
and
echo $hostSer | awk -F ':' '{print '"$i"'}' | awk -F '*' '{print $2}'
But there are wrong. Who can give me a help?
One more awk:
$ echo "$variable" | awk 'NR%2==0' RS='[*:\n]'
r13n15
r10n61
r11n18
r09n15
By setting the record separtor(RS) to *:\n , the string is broken into individual tokens, after which you can just print every 2nd line(NR%2==0).
You can use multiple separators in awk. Please try below:
h='40*r13n15:40*r10n61:40*r11n18:40*r09n15'
echo "$h"| awk -F '[:*]' '{ for (i=2;i<=NF;i+=2) print $i }'
**edited to make it generic based on the comment from RavinderSingh13.

How can I pass the output from stat to touch?

I have a korn shell script on a server running SunOS 5.9 and I need to pass the output from stat to touch in order to reset the modified timestamp of a directory after doing something to it, e.g.
#Get modified timestamp of directory
mtime=$(stat -c %y ${dirvar})
## Do something to directory that will alter its modified timestamp ##
#Reset modified timestamp of directory
touch -t "${mtime}" "${dirvar}"
How can I do this? The code above returns the error touch: bad time specification
I've tried this:
> stat -c %y ${dirvar} | awk '{ split($1, a, "-"); split($2, b, ":"); split(b[3], c, "."); print a[1]a[2]a[3]b[1]b[2]c[1]}'
Which takes this:
stat -c %y tmp
2018-12-19 11:28:41.000000000 +0000
And output it as this:
20181219112841
But I'm still getting the same touch: bad time specification error.
I have never used stat -t, but the man page says:
-t STAMP
use [[CC]YY]MMDDhhmm[.ss] instead of current time
This means, you may want to try it using this format: 201812191128.41
you can use this:
mtime=$(stat -c %Y ${dirvar})
touch -d "#${mtime}" "${dirvar}"
That uses the unix timestamp instead of an human readable date, but several linux utils accept that.
This will do what you want (at least on my Linux machine):
MTIME=$( stat now.txt | grep '^Modify:' | awk '{ print $2" "$3 }')
touch --date "$MTIME" now.txt
Alternatively, if you don't have access to the Linux touch (but do have GNU date) (operating on an so directory):
MTIME=$( stat so | grep '^Modify:' | awk '{ print $2" "$3 }')
TS=$( gdate --date "$MTIME" +%Y%m%d%H%M.%S )
touch -t $TS so
If you don't have access to GNU date, you will have to assemble the timestamp from the output of stat with something like:
mtime=$( stat so | grep '^Modify:' | awk '{ print $2" "$3 }')
yy=$( echo $mtime | cut -f1 -d- )
MM=$( echo $mtime | cut -f2 -d- )
DD=$( echo $mtime | cut -f3 -d- | cut -f1 -d\ )
hhmmss=$(echo $mtime | awk '{ print $2 }' )
hh=$( echo $hhmmss | cut -f1 -d: )
mm=$( echo $hhmmss | cut -f2 -d: )
ss=$( echo $hhmmss | cut -f3 -d: | cut -f1 -d. )
echo ${yy}${MM}${DD}
echo ${hh}${mm}.${ss}
ts=${yy}${MM}${DD}${hh}${mm}.${ss}
touch -t $ts so
Keep in mind that the act of setting the time changes the last changed time so you can't use this technique to cover your tracks if you modify a directory and hope to back date the directory to avoid detection.

Using awk to modify output

I have a command that is giving me the output:
/home/konnor/md5sums:ea66574ff0daad6d0406f67e4571ee08 counted-file.xml.20131003-083611
I need the output to be:
ea66574ff0daad6d0406f67e4571ee08 counted-file.xml
The closest I got was:
$ echo /home/konnor/md5sums:ea66574ff0daad6d0406f67e4571ee08 counted-file.xml.20131003-083611 | awk '{ printf "%s", $1 }; END { printf "\n" }'
/home/konnor/md5sums:ea66574ff0daad6d0406f67e4571ee08
I'm not familiar with awk but I believe this is the command I want to use, any one have any ideas?
Or just a sed oneliner:
echo /home/konnor/md5sums:ea66574ff0daad6d0406f67e4571ee08 counted-file.xml.20131003-083611 \
| sed -E 's/.*:(.*\.xml).*/\1/'
$ echo "/home/konnor/md5sums:ea66574ff0daad6d0406f67e4571ee08 counted-file.xml.20131003-083611" |
cut -d: -f2 |
cut -d. -f1-2
ea66574ff0daad6d0406f67e4571ee08 counted-file.xml
Note that this relies on the dot . being present as in counted-file.xml.
$ awk -F[:.] -v OFS="." '{print $2,$3}' <<< "/home/konnor/md5sums:ea66574ff0daad6d0406f67e4571ee08 counted-file.xml.20131003-083611"
ea66574ff0daad6d0406f67e4571ee08 counted-file.xml
not sure if this is ok for you:
sed 's/^.*:\(.*\)\.[^.]*$/\1/'
with your example:
kent$ echo "/home/konnor/md5sums:ea66574ff0daad6d0406f67e4571ee08 counted-file.xml.20131003-083611"|sed 's/^.*:\(.*\)\.[^.]*$/\1/'
ea66574ff0daad6d0406f67e4571ee08 counted-file.xml
this grep line works too:
grep -Po ':\K.*(?=\..*?$)'

Unix cut operation

I have a string like this:
uid=2560(jdihenia) gid=1000(undergrad)
I want to just get the undergrad part in to a variable name var1. So I used a command
var1=`echo "uid=2560(jdihenia) gid=1000(undergrad)" | cut -d "(" -f 3`
but this will assign the value undergrad) in to var1. Can you please tell me how can I get just the undergrad part in to the variable var1?
If you want the literal text "undergrad" in the brackets, this should work:
cut -d "(" -f 2 <text> | cut -d ")" -f 1
or equivalently
echo <text> | cut -d "(" -f 2 | cut -d ")" -f 1
If this string comes from id, then you can just call id -gn instead.
var1=$(cmd |sed 's/.*(\([^)]*\))/\1/')
var1="uid=2560(jdihenia) gid=1000(undergrad)"
var1=${var1#*\(*\(}
var1=${var1%%\)*}
echo "$str" | awk -F'[()]' '{print $4}'
var1=$( echo "uid=2560(jdihenia) gid=1000(undergrad)" | grep -Po 'gid=.*\(\K.*(?=\))')

Resources