diff --git a/cfg/config.go b/cfg/config.go
index 424f6ad..3d4840a 100644
--- a/cfg/config.go
+++ b/cfg/config.go
@@ -28,7 +28,7 @@ import (
)
const DefaultSeparator string = `(\s\s+|\t)`
-const Version string = "v1.3.0"
+const Version string = "v1.3.1"
const MAXPARTS = 2
var DefaultConfigfile = os.Getenv("HOME") + "/.config/tablizer/config"
@@ -67,9 +67,10 @@ type Config struct {
UseFuzzySearch bool
UseHighlight bool
- SortMode string
- SortDescending bool
- SortByColumn int
+ SortMode string
+ SortDescending bool
+ SortByColumn string // 1,2
+ UseSortByColumn []int // []int{1,2}
TransposeColumns string // 1,2
UseTransposeColumns []int // []int{1,2}
diff --git a/cmd/root.go b/cmd/root.go
index 057794b..afbf0df 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -151,7 +151,7 @@ func Execute() {
"Transpose the speficied columns (separated by ,)")
// sort options
- rootCmd.PersistentFlags().IntVarP(&conf.SortByColumn, "sort-by", "k", 0,
+ rootCmd.PersistentFlags().StringVarP(&conf.SortByColumn, "sort-by", "k", "",
"Sort by column (default: 1)")
// sort mode, only 1 allowed
diff --git a/cmd/tablizer.go b/cmd/tablizer.go
index 4139129..71f5b21 100644
--- a/cmd/tablizer.go
+++ b/cmd/tablizer.go
@@ -15,7 +15,7 @@ SYNOPSIS
-N, --no-color Disable pattern highlighting
-H, --no-headers Disable headers display
-s, --separator string Custom field separator
- -k, --sort-by int Sort by column (default: 1)
+ -k, --sort-by int|name Sort by column (default: 1)
-z, --fuzzy Use fuzzy search [experimental]
-F, --filter field=reg Filter given field with regex, can be used multiple times
-T, --transpose-columns string Transpose the speficied columns (separated by ,)
@@ -103,10 +103,19 @@ DESCRIPTION
highlighted. You can disable this behavior with the -N option.
Use the -k option to specify by which column to sort the tabular data
- (as in GNU sort(1)). The default sort column is the first one. To
- disable sorting at all, supply 0 (Zero) to -k. The default sort order is
- ascending. You can change this to descending order using the option -D.
- The default sort order is by string, but there are other sort modes:
+ (as in GNU sort(1)). The default sort column is the first one. You can
+ specify column numbers or names. Column numbers start with 1, names are
+ case insensitive. You can specify multiple columns separated by comma to
+ sort, but the type must be the same. For example if you want to sort
+ numerically, all columns must be numbers. If you use column numbers,
+ then be aware, that these are the numbers before column extraction. For
+ example if you have a table with 4 columns and specify "-c4", then only
+ 1 column (the fourth) will be printed, however if you want to sort by
+ this column, you'll have to specify "-k4".
+
+ The default sort order is ascending. You can change this to descending
+ order using the option -D. The default sort order is by alphanumeric
+ string, but there are other sort modes:
-a --sort-age
Sorts duration strings like "1d4h32m51s".
@@ -392,7 +401,7 @@ Operational Flags:
-N, --no-color Disable pattern highlighting
-H, --no-headers Disable headers display
-s, --separator string Custom field separator
- -k, --sort-by int Sort by column (default: 1)
+ -k, --sort-by int|name Sort by column (default: 1)
-z, --fuzzy Use fuzzy search [experimental]
-F, --filter field=reg Filter given field with regex, can be used multiple times
-T, --transpose-columns string Transpose the speficied columns (separated by ,)
diff --git a/lib/helpers.go b/lib/helpers.go
index 176e64e..32b6705 100644
--- a/lib/helpers.go
+++ b/lib/helpers.go
@@ -99,6 +99,19 @@ func PrepareTransposerColumns(conf *cfg.Config, data *Tabdata) error {
return nil
}
+// output option, prepare -k1,2 sort fields
+func PrepareSortColumns(conf *cfg.Config, data *Tabdata) error {
+ // -c columns
+ usecolumns, err := PrepareColumnVars(conf.SortByColumn, data)
+ if err != nil {
+ return err
+ }
+
+ conf.UseSortByColumn = usecolumns
+
+ return nil
+}
+
func PrepareColumnVars(columns string, data *Tabdata) ([]int, error) {
if columns == "" {
return nil, nil
diff --git a/lib/io.go b/lib/io.go
index c0dd937..86954b8 100644
--- a/lib/io.go
+++ b/lib/io.go
@@ -48,6 +48,11 @@ func ProcessFiles(conf *cfg.Config, args []string) error {
return err
}
+ err = PrepareSortColumns(conf, &data)
+ if err != nil {
+ return err
+ }
+
err = PrepareColumns(conf, &data)
if err != nil {
return err
diff --git a/lib/printer.go b/lib/printer.go
index 7adcd00..3189060 100644
--- a/lib/printer.go
+++ b/lib/printer.go
@@ -33,15 +33,17 @@ import (
)
func printData(writer io.Writer, conf cfg.Config, data *Tabdata) {
- // add numbers to headers and remove this we're not interested in
+ // Sort the data first, before headers+entries are being
+ // reduced. That way the user can specify any valid column to sort
+ // by, independently if it's being used for display or not.
+ sortTable(conf, data)
+
+ // add numbers to headers and remove those we're not interested in
numberizeAndReduceHeaders(conf, data)
// remove unwanted columns, if any
reduceColumns(conf, data)
- // sort the data
- sortTable(conf, data)
-
switch conf.OutputMode {
case cfg.Extended:
printExtendedData(writer, conf, data)
diff --git a/lib/printer_test.go b/lib/printer_test.go
index 73ced90..0939028 100644
--- a/lib/printer_test.go
+++ b/lib/printer_test.go
@@ -63,7 +63,7 @@ var tests = []struct {
name string // so we can identify which one fails, can be the same
// for multiple tests, because flags will be appended to the name
sortby string // empty == default
- column int // sort by this column, 0 == default first or NO Sort
+ column int // sort by this column (numbers start by 1)
desc bool // sort in descending order, default == ascending
nonum bool // hide numbering
mode int // shell, orgtbl, etc. empty == default: ascii
@@ -162,7 +162,7 @@ DURATION(2): 33d12h
//------------------------ SORT TESTS
{
- name: "sortbycolumn",
+ name: "sortbycolumn3",
column: 3,
sortby: "numeric",
desc: false,
@@ -173,7 +173,7 @@ beta 1d10h5m1s 33 3/1/2014
alpha 4h35m 170 2013-Feb-03`,
},
{
- name: "sortbycolumn",
+ name: "sortbycolumn4",
column: 4,
sortby: "time",
desc: false,
@@ -184,7 +184,7 @@ alpha 4h35m 170 2013-Feb-03
beta 1d10h5m1s 33 3/1/2014`,
},
{
- name: "sortbycolumn",
+ name: "sortbycolumn2",
column: 2,
sortby: "duration",
desc: false,
@@ -251,15 +251,14 @@ DURATION(2) WHEN(4)
func TestPrinter(t *testing.T) {
for _, testdata := range tests {
- testname := fmt.Sprintf("print-sortcol-%d-desc-%t-sortby-%s-mode-%d-usecolumns-%s",
- testdata.column, testdata.desc, testdata.sortby, testdata.mode, testdata.usecolstr)
+ testname := fmt.Sprintf("print-%s-%d-desc-%t-sortby-%s-mode-%d-usecolumns-%s",
+ testdata.name, testdata.column, testdata.desc, testdata.sortby, testdata.mode, testdata.usecolstr)
t.Run(testname, func(t *testing.T) {
// replaces os.Stdout, but we ignore it
var writer bytes.Buffer
// cmd flags
conf := cfg.Config{
- SortByColumn: testdata.column,
SortDescending: testdata.desc,
SortMode: testdata.sortby,
OutputMode: testdata.mode,
@@ -268,6 +267,10 @@ func TestPrinter(t *testing.T) {
NoColor: true,
}
+ if testdata.column > 0 {
+ conf.UseSortByColumn = []int{testdata.column}
+ }
+
conf.ApplyDefaults()
// the test checks the len!
diff --git a/lib/sort.go b/lib/sort.go
index 2d41bf9..5d65e3f 100644
--- a/lib/sort.go
+++ b/lib/sort.go
@@ -18,6 +18,7 @@ along with this program. If not, see .
package lib
import (
+ "cmp"
"regexp"
"sort"
"strconv"
@@ -27,34 +28,41 @@ import (
)
func sortTable(conf cfg.Config, data *Tabdata) {
- if conf.SortByColumn <= 0 {
+ if len(conf.UseSortByColumn) == 0 {
// no sorting wanted
return
}
- // slightly modified here to match internal array indicies
- col := conf.SortByColumn
-
- col-- // ui starts counting by 1, but use 0 internally
-
// sanity checks
if len(data.entries) == 0 {
return
}
- if col >= len(data.headers) {
- // fall back to default column
- col = 0
- }
-
// actual sorting
sort.SliceStable(data.entries, func(i, j int) bool {
- return compare(&conf, data.entries[i][col], data.entries[j][col])
+ // holds the result of a sort of one column
+ comparators := []int{}
+
+ // iterate over all columns to be sorted, conf.SortMode must be identical!
+ for _, column := range conf.UseSortByColumn {
+ comparators = append(comparators, compare(&conf, data.entries[i][column-1], data.entries[j][column-1]))
+ }
+
+ // return the combined result
+ res := cmp.Or(comparators...)
+
+ switch res {
+ case 0:
+ return true
+ default:
+ return false
+ }
+
})
}
// config is not modified here, but it would be inefficient to copy it every loop
-func compare(conf *cfg.Config, left string, right string) bool {
+func compare(conf *cfg.Config, left string, right string) int {
var comp bool
switch conf.SortMode {
@@ -88,7 +96,12 @@ func compare(conf *cfg.Config, left string, right string) bool {
comp = !comp
}
- return comp
+ switch comp {
+ case true:
+ return 0
+ default:
+ return 1
+ }
}
/*
diff --git a/lib/sort_test.go b/lib/sort_test.go
index 4d19cfa..83df8b3 100644
--- a/lib/sort_test.go
+++ b/lib/sort_test.go
@@ -53,18 +53,18 @@ func TestCompare(t *testing.T) {
mode string
a string
b string
- want bool
+ want int
desc bool
}{
// ascending
- {"numeric", "10", "20", true, false},
- {"duration", "2d4h5m", "45m", false, false},
- {"time", "12/24/2022", "1/1/1970", false, false},
+ {"numeric", "10", "20", 0, false},
+ {"duration", "2d4h5m", "45m", 1, false},
+ {"time", "12/24/2022", "1/1/1970", 1, false},
// descending
- {"numeric", "10", "20", false, true},
- {"duration", "2d4h5m", "45m", true, true},
- {"time", "12/24/2022", "1/1/1970", true, true},
+ {"numeric", "10", "20", 1, true},
+ {"duration", "2d4h5m", "45m", 0, true},
+ {"time", "12/24/2022", "1/1/1970", 0, true},
}
for _, testdata := range tests {
@@ -75,7 +75,7 @@ func TestCompare(t *testing.T) {
c := cfg.Config{SortMode: testdata.mode, SortDescending: testdata.desc}
got := compare(&c, testdata.a, testdata.b)
if got != testdata.want {
- t.Errorf("got %t, want %t", got, testdata.want)
+ t.Errorf("got %d, want %d", got, testdata.want)
}
})
}
diff --git a/t/testtable3 b/t/testtable3
new file mode 100644
index 0000000..4d8dac7
--- /dev/null
+++ b/t/testtable3
@@ -0,0 +1,6 @@
+NAME READY STATUS STARTS AGE
+alertmanager-kube-prometheus-alertmanager-0 2/2 Running 35 11d
+kube-prometheus-blackbox-exporter-5d85b5d8f4-tskh7 1/1 Running 17 1h44m
+grafana-fcc54cbc9-bk7s8 1/1 Running 17 1d
+kube-prometheus-kube-state-metrics-b4cd9487-75p7f 1/1 Running 20 45m
+kube-prometheus-node-exporter-bfzpl 1/1 Running 17 54s
diff --git a/t/testtable4 b/t/testtable4
new file mode 100644
index 0000000..cc06395
--- /dev/null
+++ b/t/testtable4
@@ -0,0 +1,4 @@
+ONE TWO
+1 4
+3 1
+5 2
diff --git a/tablizer.1 b/tablizer.1
index 49b640e..73dd6b4 100644
--- a/tablizer.1
+++ b/tablizer.1
@@ -133,7 +133,7 @@
.\" ========================================================================
.\"
.IX Title "TABLIZER 1"
-.TH TABLIZER 1 "2025-01-14" "1" "User Commands"
+.TH TABLIZER 1 "2025-01-15" "1" "User Commands"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
@@ -153,7 +153,7 @@ tablizer \- Manipulate tabular output of other programs
\& \-N, \-\-no\-color Disable pattern highlighting
\& \-H, \-\-no\-headers Disable headers display
\& \-s, \-\-separator string Custom field separator
-\& \-k, \-\-sort\-by int Sort by column (default: 1)
+\& \-k, \-\-sort\-by int|name Sort by column (default: 1)
\& \-z, \-\-fuzzy Use fuzzy search [experimental]
\& \-F, \-\-filter field=reg Filter given field with regex, can be used multiple times
\& \-T, \-\-transpose\-columns string Transpose the speficied columns (separated by ,)
@@ -250,11 +250,20 @@ By default, if a \fBpattern\fR has been speficied, matches will be
highlighted. You can disable this behavior with the \fB\-N\fR option.
.PP
Use the \fB\-k\fR option to specify by which column to sort the tabular
-data (as in \s-1GNU\s0 \fBsort\fR\|(1)). The default sort column is the first one. To
-disable sorting at all, supply 0 (Zero) to \-k. The default sort order
-is ascending. You can change this to descending order using the option
-\&\fB\-D\fR. The default sort order is by string, but there are other sort
-modes:
+data (as in \s-1GNU\s0 \fBsort\fR\|(1)). The default sort column is the first
+one. You can specify column numbers or names. Column numbers start
+with 1, names are case insensitive. You can specify multiple columns
+separated by comma to sort, but the type must be the same. For example
+if you want to sort numerically, all columns must be numbers. If you
+use column numbers, then be aware, that these are the numbers before
+column extraction. For example if you have a table with 4 columns and
+specify \f(CW\*(C`\-c4\*(C'\fR, then only 1 column (the fourth) will be printed,
+however if you want to sort by this column, you'll have to specify
+\&\f(CW\*(C`\-k4\*(C'\fR.
+.PP
+The default sort order is ascending. You can change this to
+descending order using the option \fB\-D\fR. The default sort order is by
+alphanumeric string, but there are other sort modes:
.IP "\fB\-a \-\-sort\-age\fR" 4
.IX Item "-a --sort-age"
Sorts duration strings like \*(L"1d4h32m51s\*(R".
diff --git a/tablizer.pod b/tablizer.pod
index 90fd331..8f170ae 100644
--- a/tablizer.pod
+++ b/tablizer.pod
@@ -14,7 +14,7 @@ tablizer - Manipulate tabular output of other programs
-N, --no-color Disable pattern highlighting
-H, --no-headers Disable headers display
-s, --separator string Custom field separator
- -k, --sort-by int Sort by column (default: 1)
+ -k, --sort-by int|name Sort by column (default: 1)
-z, --fuzzy Use fuzzy search [experimental]
-F, --filter field=reg Filter given field with regex, can be used multiple times
-T, --transpose-columns string Transpose the speficied columns (separated by ,)
@@ -106,11 +106,20 @@ By default, if a B has been speficied, matches will be
highlighted. You can disable this behavior with the B<-N> option.
Use the B<-k> option to specify by which column to sort the tabular
-data (as in GNU sort(1)). The default sort column is the first one. To
-disable sorting at all, supply 0 (Zero) to -k. The default sort order
-is ascending. You can change this to descending order using the option
-B<-D>. The default sort order is by string, but there are other sort
-modes:
+data (as in GNU sort(1)). The default sort column is the first
+one. You can specify column numbers or names. Column numbers start
+with 1, names are case insensitive. You can specify multiple columns
+separated by comma to sort, but the type must be the same. For example
+if you want to sort numerically, all columns must be numbers. If you
+use column numbers, then be aware, that these are the numbers before
+column extraction. For example if you have a table with 4 columns and
+specify C<-c4>, then only 1 column (the fourth) will be printed,
+however if you want to sort by this column, you'll have to specify
+C<-k4>.
+
+The default sort order is ascending. You can change this to
+descending order using the option B<-D>. The default sort order is by
+alphanumeric string, but there are other sort modes:
=over