To supplement a little:
Basic format for printf
in text is:
%s # Print as is
%10 # Right justify minimum width print 10
%-10 # Left justify minimum width print 10
%.10 # Max width 10
%10.10 # Max width 10, min width print 10
%-10.10 # Left justify, max width 10, min width print 10
%*s # Same as above, but get number from arguments
%-*s # Same as above, but get number from arguments
...
When one get long patterns it can become a bit messy to keep track on where and which etc. One way to make it a bit easier could be something like this:
#!/bin/bash
usage()
{
printf "Usage: %s <FILE>\n" "$(basename "$0")" >&2
[[ -n "$1" ]] && echo "$1"
exit 1
}
if [[ ! -t 0 ]]; then
: # Piped to
elif [[ $# -eq 0 ]]; then
usage "Missing file."
elif [[ ! -r "$1" ]]; then
usage "Unable to read \`$1'."
else
# Accept input from file to file descriptor 0, aka stdin
exec 0< "$1"
fi
fmt=""
fmt="$fmt%s|" # F1
fmt="$fmt%-24.24s|" # F2
fmt="$fmt%-30s|" # F3
fmt="$fmt%-10.10s|" # F4
fmt="$fmt%-10.10s|" # F5
fmt="$fmt%-10s|" # F6
fmt="$fmt%-2.2s|" # F7
fmt="$fmt%-2.2s|\n" # F8
# Set IFS to newline and bar and read fields
# assigning them to f1 ... f8
#
while IFS=$'\n'"|" read f1 f2 f3 f4 f5 f6 f7 f8; do
printf "$fmt"\
"$f1" "$f2" "$f3" "$f4" \
"$f5" "$f6" "$f7" "$f8"
done <&0
Or. e.g.:
while IFS=$'\n'"|" read f1 f2 f3 f4 f5 f6 f7 f8; do
printf "%s|%-*.*s|%-*s\n" \
"$f1" \
24 24 "$f2" \
30 "$f3"
done < "input"
If it is only line parsing then awk is an good alternative. e.g.:
#!/usr/bin/awk -f
BEGIN {FS="|"}
/^/ {
printf "%s|%-24.24s|%-30s|%-10.10s|%-10.10s|%-10s\n",
$1, $2, $3, $4, $5, $6
}
Or:
#!/usr/bin/awk -f
BEGIN {
FS="|"
}
/^/ {
printf "%s|%-*.*s|%-*s|%-*.*s|%-*.*s|%-*s\n",
$1,
24, 24, $2,
30, $3,
10, 10, $4,
10, 10, $5,
10, $6
}
Alternatively, if your date
doesn't support %s
, with many awk
implementations, you can use srand()
to get the current Unix time:
awk 'BEGIN{srand(); d = srand() - 3 * 30 * 24 * 60 * 60}; $1 > d' < a.txt
Or use perl
:
perl -ne'BEGIN{$d = time - 3 * 30 * 24 * 60 * 60}print if $_ > $d' < a.txt
Note that 3 months here are counted as a fixed period of 90 days of 86400 seconds each.
If instead you want: not before the same day of the month, 3 months ago at the same time of the day (if now is 2013-12-15 21:02:01, that would be since 2013-09-15 21:02:01 (91 days and 1 hour ago in a European Union timezone for instance)), see @Zelda's answer, or:
perl -MPOSIX -ne 'BEGIN{@t=localtime;$t[4]-=3;$d=mktime @t}
print if $_ > $d' < a.txt
(with the caveat that on May 29 (non leap year), May 30 & 31, Jul 31st and Dec 31st, the 3-months ago date will be the same as for GNU date -d '3 months ago'
).
If instead, you mean this month, the previous, or the one before the previous (if today is 2013-12-15, that would be since 2013-10-01 00:00:00), that would be:
perl -MPOSIX -ne 'BEGIN{@t=localtime;$d=mktime 0,0,0,1,$t[4]-2,$t[5]}
print if $_ >= $d' < a.txt
Best Answer
Use
for your example