cut command to remove seconds from time. shell scripting - linux

Lets say we got date and time to a log in the format of
2022-05-18-11:57:140100
I need to remove seconds from this time. It means the final output should be like
2022-05-18-11:57
I tried the following
echo "2022-05-18-11:57:140100" | rev | cut -d/ -f6- | rev`:"
this was not successful and I have no idea how this cut command works. can anybody explain. Thanks in advance

1st solution: With GNU awk you can simply do it like following. Simple explanation would be, set FS and OFS as : and then in main block of awk program decrease NF with 1 and print the line.
echo "2022-05-18-11:57:140100" | awk 'BEGIN{FS=OFS=":"} NF--'
2nd solution: In any awk using awk's match function please try following.
echo "2022-05-18-11:57:140100" | awk 'match($0,/.*:/){print substr($0,RSTART,RLENGTH-1)}'
3rd solution: Using sed's capability of capturing groups(keep values in temp buffer) please try following code.
echo "2022-05-18-11:57:140100" | sed -E 's/(^[^:]*):([^:]*):.*/\1:\2/'
4th solution(OP's efforts FIX): Fixing OP's efforts using rev + cut + rev combination here.
echo "2022-05-18-11:57:140100" | rev | cut -d':' -f2- | rev

This can be done easily in bash shell also:
s='2022-05-18-11:57:140100'
echo "${s%:*}"
2022-05-18-11:57
# or else use cut
cut -d: -f1-2 <<< "$s"
2022-05-18-11:57
# or sed
sed 's/:[^:]*$//' <<< "$s"
2022-05-18-11:57

any one of these 5 solutions should work for gawk, mawk-1, mawk-2, and macos nawk :
echo "2022-05-18-11:57:140100" |
mawk2 NF=NF FS=':[^:]*$' OFS=
or
gawk -- --NF FS=':[^:]*$'
or
gawk NF-- FS=':[^:]*$'
or
nawk NF=1 FS=':[^:]*$'
or
mawk '$!_=$!_' FS=':[^:]*$'
2022-05-18-11:57
The most compacted version would be like
mawk -F':[^:]*$' NF--

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/'

How get value from text file in linux

I have some file xxx.conf in text format. I have some text "disablelog = 1" in this file.
When I use
grep -r "disablelog" oscam.conf
output is
disablelog = 1
But i need only value 1.
Do you have some idea please?
one way is to use awk to print just the value
grep -r "disablelog" oscam.conf | awk '{print $3}'
you could also use sed to replace diablelog = with empty
grep -r 'disablelog' oscam.conf | sed -e 's/disablelog = //'
If you also want to get the lines with or without space before and after = use
grep -r 'disablelog' oscam.conf | sed 's/disablelog\s*=\s*//'
above command will also match
disablelog=1
Assuming you need it as a var in a script:
#!/bin/bash
DISABLELOG=$(awk -F= '/^.*disablelog/{gsub(/ /,"",$2);print $2}' /path/to/oscam.conf)
echo $DISABLELOG
When calling this script, the output should be 1.
Edit: No matter wether there is whitespace or not between the equals sign and the value, the above will handle that. The regex should be anchored in either way to improve performance.
Try:
grep -r "disablelog" oscam.conf | awk -F= '{print $2}'
Just for fun a solution without awk
grep -r disablelog | cut -d= -f2 | xargs
xargs is used here to trim the whitespace

how to print tail of path filename using awk

I've searched it with no success.
I have a file with pathes.
I want to print the tail of a all pathes.
for example (for every line in file):
/homes/work/abc.txt
--> abc.txt
Does anyone know how to do it?
Thanks
awk -F "/" '{print $NF}' input.txt
will give output of:
abc1.txt
abc2.txt
abc3.txt
for:
$>cat input.txt
text path/to/file/abc1.txt
path/to/file/abc2.txt
path/to/file/abc3.txt
How about this awk
echo "/homes/work/abc.txt" | awk '{sub(/.*\//,x)}1'
abc.txt
Since .* is greedy, it will continue until last /
So here we remove all until last / with x, and since x is empty, gives nothing.
Thors version
echo "/homes/work/abc.txt" | awk -F/ '$0=$NF'
abc.txt
NB this will fail for /homes/work/0 or 0,0 etc so better use:
echo "/homes/work/abc.txt" | awk -F/ '{$0=$NF}1'
awk solutions are already provided by #Jotne and #bashophil
Here are some other variations (just for fun)
Using sed
sed 's:.*/::' file
Using grep
grep -oP '(.*/)?\K.*' file
Using cut - added by #Thor
rev file | cut -d/ -f1 | rev
Using basename - suggested by #fedorqui and #EdMorton
while IFS= read -r line; do
basename "$line"
done < file

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.*(?=\..*?$)'

Select first part of string

How do I pull a substring from a string. For example, from the string:
'/home/auto/gift/surprise'
take only:
'/home/auto/'
Note that '/home/auto/gift/surprise' may vary, i.e., instead of having 4 directory levels, it may go to 6 or 8, yet I'm only interested in the first 2 folders.
Here's what I've tried so far, without success:
$ pwd
'/home/auto/gift/surprise'
$ pwd | sed 's,^\(.*/\)\?\([^/]*\),\1,'
'/home/auto/gift/'
I think it is better to use cut for this:
$ echo "/home/auto/gift/surpris" | cut -d/ -f1-3
/home/auto
$ echo "/home/auto/gift/surpris/bla/bla" | cut -d/ -f1-3
/home/auto
Note that cut -d/ -f1-3 means: strip the string based on the delimiter /, then print from the 1st to the 3rd parts.
Or also awk:
$ echo "/home/auto/gift/surpris" | awk -F/ 'OFS="/" {print $1,$2,$3}'
/home/auto
$ echo "/home/auto/gift/surpris/bla/bla" | awk -F/ 'OFS="/" {print $1,$2,$3}'
/home/auto
You may use parameter substitution, which is POSIX defined:
$ s="/home/auto/gift/surprise"
$ echo ${s%/*/*}
/home/auto

Resources