一个能够生成 Markdown 表格的 Bash 脚本

哈喽大家好,我是咸鱼。

今天分享一个很实用的 bash 脚本,可以通过手动提供单元格内容和列数或者将带有分隔符的文件(如 CSV、TSV 文件)转换为 Markdown 表格。

源代码在文末哦!原文链接:https://josh.fail/2022/pure-bash-markdown-table-generator/

具体功能:

  • 手动生成表格:允许用户输入表格内容和列数,生成标准的 Markdown 格式表格。
  • 文件转换:可以将 CSV 或 TSV 文件转换为 Markdown 表格。
  • 选项支持:支持指定列数、设置分隔符、解析 CSV/TSV 文件等选项。

主要选项:

  • -COLUMNS:设置生成表格的列数。
  • -sSEPARATOR:自定义输入文件的列分隔符。
  • --csv--tsv:分别用于解析 CSV 和 TSV 文件。

几个月前,我想要一个便携式的 Markdown 表格生成器,于是写了这个 markdown-table 脚本。

一开始我只是想传入一堆参数和列数,并让它生成相应的 Markdown 表格。就像下面的例子:

markdown-table -4   "Heading 1"  "Heading 2" "Heading 3" "Heading 4"   "Hi"         "There"     "From"      "Markdown!"   "Everything" "Is"        "So"        "Nicely Aligned!" 

当我实现了这一功能后,我意识到还可以添加支持解析带有自定义分隔符的文件,比如 CSV 或 TSV。

markdown-table --tsv < test.tsv 

上面两种方法都会生成一个 Markdown 表格:

| Heading 1  | Heading 2 | Heading 3 | Heading 4      | | ---------- | --------- | --------- | -------------- | | Hi         | There     | From      | Markdown       | | Everything | Is        | So        | Nicely Aligned | 
#!/usr/bin/env bash # Usage: markdown-table -COLUMNS [CELLS] #        markdown-table -sSEPARATOR < file # # NAME #   markdown-table -- generate markdown tables # # SYNOPSIS #   markdown-table -COLUMNS [CELLS] #   markdown-table -sSEPARATOR < file # # DESCRIPTION #   markdown-table helps generate markdown tables. Manually supply arguments #   and a column count to generate a table, or pass in a delimited file to #   convert to a table. # # OPTIONS #   -COLUMNS #       Number of columns to include in output. # #   -sSEPARATOR #       String used to separate columns in input files. # #   --csv #       Shortcut for `-s,` to parse CSV files. Note that this is a "dumb" CSV #       parser -- it won't work if your cells contain commas! # #   --tsv #       Shortcut for `-s$'t'` to parse TSV files. # #   -h, --help #       Prints help text and exits. # # EXAMPLES #   Build a 4 column markdown table from arguments: #     markdown-table -4  #       "Heading 1"  "Heading 2" "Heading 3" "Heading 4"  #       "Hi"         "There"     "From"      "Markdown!"  #       "Everything" "Is"        "So"        "Nicely Aligned!" # #   Convert a CSV file into a markdown table: #     markdown-table -s, < some.csv #     markdown-table --csv < some.csv # #   Convert a TSV file into a markdown table: #     markdown-table -s$'t' < test.tsv #     markdown-table --tsv < test.tsv  # Call this script with DEBUG=1 to add some debugging output if [[ "$DEBUG" ]]; then   export PS4='+ [${BASH_SOURCE##*/}:${LINENO}] '   set -x fi  set -e  # Echoes given args to STDERR # # $@ - args to pass to echo warn() {   echo "$@" >&2 }  # Print the help text for this program # # $1 - flag used to ask for help ("-h" or "--help") print_help() {   sed -ne '/^#/!q;s/^#$/# /;/^# /s/^# //p' < "$0" |     awk -v f="$1" '       f == "-h" && ($1 == "Usage:" || u) {         u=1         if ($0 == "") {           exit         } else {           print         }       }       f != "-h"       ' }  # Returns the highest number in the given arguments # # $@ - one or more numeric arguments max() {   local max=0 arg    for arg; do     (( ${arg:-0} > max )) && max="$arg"   done    printf "%s" "$max" }  # Formats a table in markdown format # # $1 - field separator string format_table() {   local fs="$1" buffer col current_col=0 current_row=0 min=3   local -a lengths=()    buffer="$(cat)"    # First pass to get column lengths   while read -r line; do     current_col=0      while read -r col; do       lengths["$current_col"]="$(max "${#col}" "${lengths[$current_col]}")"        current_col=$((current_col + 1))     done <<< "${line//$fs/$'n'}"   done <<< "$buffer"    # Second pass writes each row   while read -r line; do     current_col=0     current_row=$((current_row + 1))      while read -r col; do       printf "| %-$(max "${lengths[$current_col]}" "$min")s " "$col"        current_col=$((current_col + 1))     done <<< "${line//$fs/$'n'}"      printf "|n"      # If this is the first row, print the header dashes     if [[ "$current_row" -eq 1 ]]; then       for (( current_col=0; current_col < ${#lengths[@]}; current_col++ )); do         printf "| "         printf "%$(max "${lengths[$current_col]}" "$min")s" | tr " " -         printf " "       done        printf "|n"     fi   done <<< "$buffer" }  # Main program main() {   local arg cols i fs="##$$FS##"    while [[ $# -gt 0 ]]; do     case "$1" in       -h | --help) print_help "$1"; return 0 ;;       -[0-9]*) cols="${1:1}"; shift ;;       -s*) fs="${1:2}"; shift ;;       --csv) fs=","; shift ;;       --tsv) fs=$'t'; shift ;;       --) shift; break ;;       -*) warn "Invalid option '$1'"; return 1 ;;       *) break ;;     esac   done    if [[ -z "$fs" ]]; then     warn "Field separator can't be blank!"     return 1   elif [[ $# -gt 0 ]] && ! [[ "$cols" =~ ^[0-9]+$ ]]; then     warn "Missing or Invalid column count!"     return 1   fi    { if [[ $# -gt 0 ]]; then       while [[ $# -gt 0 ]]; do         for (( i=0; i < cols; i++ )); do           if (( i + 1 == cols )); then             printf "%s" "$1"           else             printf "%s%s" "$1" "$fs"           fi           shift         done          printf "n"       done     else       cat     fi   } | format_table "$fs" }  main "$@" 

发表评论

评论已关闭。

相关文章