In bash how can I split a column in several column

2019-07-08 04:52发布

how can I split a single column in several column of fixed dimension, for example I have a column like this:

1
2
3
4
5
6
7
8

and for size p. ex 4, I want to obtain

1 5
2 6
3 7
4 8

or for size p. ex 2, I want to obtain

1 3 5 7
2 4 6 8

标签: linux bash shell
5条回答
萌系小妹纸
2楼-- · 2019-07-08 05:45

Using awk:

awk '
  BEGIN {
    # Numbers of rows to print
    n=4;
  }
  {
    # Add to array with key = 0, 1, 2, 3, 0, 1, 2, ..
    l[(NR-1)%n] = l[(NR-1)%n] " " $0
  };
  END {
    # print the array
    for (i = 0; i < length(l); i++) {
      print l[i];
    }
  }
' file
查看更多
太酷不给撩
3楼-- · 2019-07-08 05:48

If you know the desired output width you can use column.

# Display in columns for an 80 column display
cat file | column -c 80
查看更多
等我变得足够好
4楼-- · 2019-07-08 05:52
$ cat tst.awk
{ a[NR] = $0 }
END {
    OFS=","
    numRows = (numRows ? numRows : 1)
    numCols = ceil(NR / numRows)
    for ( rowNr=1; rowNr<=numRows; rowNr++ ) {
        for ( colNr=1; colNr<=numCols; colNr++ ) {
            idx = rowNr + ( (colNr - 1) * numRows )
            printf "%s%s", a[idx], (colNr<numCols ? OFS : ORS)
        }
    }
}
function ceil(x, y){y=int(x); return(x>y?y+1:y)}

$ awk -v numRows=2 -f tst.awk file
1,3,5,7
2,4,6,8

$ awk -v numRows=4 -f tst.awk file
1,5
2,6
3,7
4,8

Note that above produces a CSV with the same number of fields in every row even when the number of input rows isn't an exact multiple of the desired number of output rows:

$ seq 10 | awk -v numRows=4 -f tst.awk
1,5,9
2,6,10
3,7,
4,8,

See https://stackoverflow.com/a/56725452/1745001 for how to do the opposite, i.e. generate a number of rows given a specified number of columns.

查看更多
何必那么认真
5楼-- · 2019-07-08 05:53

OK, this is a bit long winded and not infallible but the following should work:

td=$( mktemp -d ); split -l <rows> <file> ${td}/x ; paste $( ls -1t ${td}/x* ) ; rm -rf ${td}; unset td

Where <cols> is the number of rows you want and file is your input file. Explanation:

td=$( mktemp -d )

Creates a temporary directory so that we can put temporary files into it. Store this in td - it's possible that your shell has a td variable already but if you sub-shell for this your scope should be OK.

split -l <rows> <file> f ${td}/x

Split the original file into many smaller file, each <rows> long. These will be put into your temp directory and all files will be prefixed with x

paste $( ls -1t ${td}/x* )

Write these files out so that the lines in consecutive columns

rm -rf ${td}

Remove the files and directory.

unset td

Clean the environment.

查看更多
别忘想泡老子
6楼-- · 2019-07-08 05:58

Assuming you know the number of rows in your column (here, 8):

n=8
# to get output with 4 rows:
seq $n | pr -ts" " -$((n/4))
1 5
2 6
3 7
4 8
# to get output with 2 rows:
seq $n | pr -ts" " -$((n/2))
1 3 5 7
2 4 6 8
查看更多
登录 后发表回答