关于bash:Gar

75次阅读

共计 7252 个字符,预计需要花费 19 分钟才能阅读完成。

Gar 是一个 Bash 脚本程序,用于治理 Markdown 文档我的项目,可将 Markdown 文档汇合其转化为 HTML 文档汇合。Gar 的运行,依赖 pandoc,git,tree 以及一个能在 Shell(命令行)里关上指定网页文件的网页浏览器。Gar 默认将 Firefox 作为网页浏览器,然而可在文档我的项目根目录的 gar.conf 文件中指定其它符合要求的网页浏览器。

文档我的项目初始化

命令:gar init 文档我的项目名

例如:

$ gar init demo
[master (root-commit) 6f7dd1c] init
 1 file changed, 2 insertions(+)
 create mode 100644 gar.conf

以下命令可察看 gar init 发明了什么:

$ cd demo
$ ls -a
  ..  gar.conf  .git  output  source  图片 
$ gar tree
demo
├── gar.conf
├── output
├── source
└── 图片 
$ git log
commit 6f7dd1c23c0cc8b18eb84b6a5236605eebd2bfbf (HEAD -> master)
Author: xxx <xxx@yyy.zzz>
Date:   Tue Mar 9 07:30:53 2021 +0800

    init

文档我的项目初始化后,文档的撰写和编辑工作次要在 source 目录进行。Gar 将 Markdown 文档转化为 HTML 文档后,放在 output 子目录内。

文集创立与删除

进入 source 目录:

$ cd source

创立文集 foo:

$ gar new-class foo

可应用 gar tree 查看文档我的项目的目录变动,察看 gar new-class 发明了什么:

$ gar tree
demo
├── gar.conf
├── output
│   └── foo
├── source
│   └── foo
└── 图片
    └── foo

可一次创立多个文集:

$ gar new-class a b c

后果为:

$ gar tree
demo
├── gar.conf
├── output
│   ├── a
│   ├── b
│   ├── c
│   └── foo
├── source
│   ├── a
│   ├── b
│   ├── c
│   └── foo
└── 图片
    ├── a
    ├── b
    ├── c
    └── foo

删除文集:

$ gar remove-class a b c
$ gar tree
demo
├── gar.conf
├── output
│   └── foo
├── source
│   └── foo
└── 图片
    └── foo

可在文集里创立子文集:

$ cd foo
$ gar new-class a
$ gar tree
demo
├── gar.conf
├── output
│   └── foo
│       └── a
├── source
│   └── foo
│       └── a
└── 图片
    └── foo
        └── a

可创立文集档次序列:

$ gar new-class b/c/d/e/f
$ gar tree
demo
├── gar.conf
├── output
│   └── foo
│       ├── a
│       └── b
│           └── c
│               └── d
│                   └── e
│                       └── f
├── source
│   └── foo
│       ├── a
│       └── b
│           └── c
│               └── d
│                   └── e
│                       └── f
└── 图片
    └── foo
        ├── a
        └── b
            └── c
                └── d
                    └── e
                        └── f

将试验复盘:

$ gar remove-class a b
$ gar tree
demo
├── gar.conf
├── output
│   └── foo
├── source
│   └── foo
└── 图片
    └── foo

提醒,目前工作目录仍为 source/foo。

创立和删除文档

在文集目录内,应用 gar new-post 创立内容为空的文档。例如,在 source/foo 内创立 test.md 文档:

$ gar new-post test.md
[master 6a894eb] Added test.md
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 source/foo/test.md

查看产生了什么:

$ gar tree
demo
├── gar.conf
├── output
│   └── foo
├── source
│   └── foo
│       └── test.md
└── 图片
    └── foo
        └── test
$ git log
commit 6a894eb44cf66e95b4ff938e05c019b7218039e0 (HEAD -> master)
Author: xxx <xxx@yyy.zzz>
Date:   Tue Mar 9 08:16:49 2021 +0800

    Added test.md

commit 6f7dd1c23c0cc8b18eb84b6a5236605eebd2bfbf
Author: xxx <xxx@yyy.zzz>
Date:   Tue Mar 9 07:30:53 2021 +0800

    init

每次创立文档时,Gar 会调用 git 记录文档创立历史。

可一次创立多份空文档:

$ gar new-post a.md b.md c.md
[master 25e7d65] Added a.md b.md c.md
 3 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 source/foo/a.md
 create mode 100644 source/foo/b.md
 create mode 100644 source/foo/c.md
$ gar tree
demo
├── gar.conf
├── output
│   └── foo
├── source
│   └── foo
│       ├── a.md
│       ├── b.md
│       ├── c.md
│       └── test.md
└── 图片
    └── foo
        ├── a
        ├── b
        ├── c
        └── test

应用 gar remove-post 可删除当前工作目录下的文档。以下命令可将上述创立的文档一举删除:

$ gar remove-post test.md a.md b.md c.md
[master 189da8b] Remove test.md a.md b.md c.md
 4 files changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 source/foo/a.md
 delete mode 100644 source/foo/b.md
 delete mode 100644 source/foo/c.md
 delete mode 100644 source/foo/test.md

每次删除文档,git 会记录文档的删除历史。

通过上述操作后,这个试验性的文档我的项目又复盘为:

$ gar tree
demo
├── gar.conf
├── output
│   └── foo
├── source
│   └── foo
└── 图片
    └── foo

网页的生成和预览

记住,以后的工作目录仍然是 source/foo。上面的命令从新创立 test.md:

$ gar new-post test.md

而后用文本编辑器关上 test.md,减少以下内容:

<!--
.. title: Hello Gar!
-->

这只是一份无用的示例文档。

应用 gar convert 命令可将文档 test.md 转换为网页文件 test.html,并将其置于 文档我的项目根目录 /output/foo 目录内:

$ gar convert test.md

查看文档目录产生的变动:

$ gar tree
demo
├── gar.conf
├── output
│   └── foo
│       └── test.html
├── source
│   └── foo
│       └── test.md
└── 图片
    └── foo
        └── test

假使工作目录(以后文集)内有多份文档,也能够一次性将其转换为一组网页文件,例如:

$ gar convert test.md a.md b.md c.md

应用 gar preview 命令,可将文档转化为网页文件,并由 Gar 默认的网页浏览器关上:

$ gar preview test.md

gar preview 不反对多份文档一次性转换和预览。

附录

Gar 的全副代码:

#!/bin/bash

SCRIPT_PATH=$(cd "$(dirname"${BASH_SOURCE[0]}")" && pwd)

GAR_CONF=gar.conf
SOURCE=source
IMAGES= 图片
OUTPUT=output

function error_msg {
    echo $1
    exit -1
}

function goto_root {if [ ! -e $GAR_CONF]
    then
        if [$(pwd) = / ]
        then
            echo "gar.conf Not found!"
        else
            cd ..
            goto_root  
        fi
    fi
}

function class_name {
    TARGET_PATH=$1
    goto_root
    SOURCE_PATH=$(pwd)/$SOURCE/
    echo ${TARGET_PATH//$SOURCE_PATH/}
}

function get_title {NAME=${1%.md}
    # 将文件名里用于距离中文和英文的短线替换为空格
    L_SPACE_PAT='s/\([^a-zA-Z]\)-/\1 /g'
    R_SPACE_PAT='s/-\([^a-zA-Z]\)/ \1/g'
    FANCY_NAME="$(echo $NAME | sed -e"$L_SPACE_PAT; $R_SPACE_PAT")"
    # 文章题目
    PREFIX="^[[:space:]]*\.\.[[:space:]]*title:[[:space:]]*"
    TITLE=$(grep -o "${PREFIX}.*$" $1 | sed -e "s/${PREFIX}\(.*\)$/\1/g")
    if [-z "$TITLE"]
    then
        TITLE=$FANCY_NAME
    fi
    echo $TITLE
}

function markdown_to_html {HTML=$OUTPUT/$1/${2%.*}.html
    pandoc $SOURCE/$1/$2 -s --mathjax \
           -c $SCRIPT_PATH/gar.css \
           --highlight-style pygments \
           --metadata title="$TITLE" -o $HTML
}

case $1 in
    init)
        case $2 in
            "")
                error_msg "You should tell me the name of the project!"
                ;;
            *)
                mkdir $2
                cd $2
                echo '#!/bin/bash' > $GAR_CONF
                echo "BROWSER_FOR_GAR=firefox" >> $GAR_CONF
                mkdir $SOURCE $OUTPUT $IMAGES
                git init -q
                git add .
                git commit -a -m "init"
                ;;
        esac
        ;;
    new-class)
        case $2 in
            "")
                error_msg "You should tell me the name of the posts class!"
                ;;
            *)
                for i in ${@:2}
                do
                    MARK=$(pwd)
                    mkdir -p $i
                    cd $i
                    CLASS_NAME=$(class_name $MARK/$i)
                    
                    goto_root
                    mkdir -p $IMAGES/$CLASS_NAME
                    mkdir -p $OUTPUT/$CLASS_NAME
                    cd $MARK
                done
                ;;
        esac
        ;;
    remove-class)
        case $2 in
            "")
                error_msg "You should tell me the name of the posts class!"
                ;;
            *)
                for i in ${@:2}
                do
                    MARK=$(pwd)
                    rm -rf $i
                    CLASS_NAME=$(class_name $MARK/$i)
                    
                    goto_root
                    rm -rf $IMAGES/$CLASS_NAME
                    rm -rf $OUTPUT/$CLASS_NAME
                    cd $MARK
                done
                ;;
        esac
        ;;
    new-post)
        case $2 in
            "")
                error_msg "You should tell me the name of the post!"
                ;;
            *)
                MARK=$(pwd)
                CLASS_NAME=$(class_name $MARK)
                for i in ${@:2}
                do
                    touch $i
                    goto_root
                    mkdir -p $IMAGES/$CLASS_NAME/${i%.*}
                    cd $MARK
                done
                goto_root
                git add .
                DOCUMENTS="${@:2}"
                git commit -a -m "Added $DOCUMENTS"
                ;;
        esac
        ;;
    remove-post)
        case $2 in
            "")
                error_msg "You should tell me the name of the post!"
                ;;
            *)
                MARK=$(pwd)
                for i in ${@:2}
                do
                    if [! -e $i]
                    then
                        error_msg "The file you want to remove is not found!"
                    fi
                    rm $i
                    CLASS_NAME=$(class_name $MARK)
                    goto_root
                    rm -rf $IMAGES/$CLASS_NAME/${i%.*}
                    HTML_OF_POST=$OUTPUT/$CLASS_NAME/${i%.*}.html
                    if [-e HTML_OF_POST]
                    then
                        rm $HTML_OF_POST
                    fi
                    cd $MARK
                done
                goto_root
                git add .
                DOCUMENTS="${@:2}"
                git commit -a -m "Remove $DOCUMENTS"
                ;;
        esac
        ;;
    rename)
        case $2 in
            "")
                error_msg "You should tell me the name of the post you want to rename!"
                ;;
            *)
                if [! -e $2]
                then
                    error_msg "The file you want to rename is not found!"
                fi
                case $3 in
                    "")
                        error_msg "You should tell me new name of the post!"
                        ;;
                    *)
                        mv $2 $3
                        CLASS_NAME=$(class_name $(pwd))
                        goto_root
                        mv $IMAGES/$CLASS_NAME/${2%.*} $IMAGES/$CLASS_NAME/${3%.*}
                        mv $OUTPUT/$CLASS_NAME/${2%.*} $OUTPUT/$CLASS_NAME/${3%.*}
                        git add .
                        git commit -a -m "Rename $2 $3"
                        ;;
                esac
                ;;
        esac
        ;;
    convert)
        case $2 in
            "")
                error_msg "You should tell me the name of the post!"
                ;;
            *)
                MARK=$(pwd)
                for i in ${@:2}
                do
                    TITLE=$(get_title $i)
                    CLASS_NAME=$(class_name $MARK)
                    goto_root
                    markdown_to_html $CLASS_NAME $i
                    cd $MARK
                done
                ;;
            esac
        ;;
    preview)
        case $2 in
            "")
                error_msg "You should tell me the name of the post!"
                ;;
            *)  
                TITLE=$(get_title $2)
                CLASS_NAME=$(class_name $(pwd))
                goto_root
                source gar.conf
                $BROWSER_FOR_GAR $OUTPUT/$CLASS_NAME/${2%.*}.html
                ;;
            esac
        ;;
    tree)
        goto_root
        GAR_ROOT=$(basename $(pwd))
        cd ..
        tree $GAR_ROOT
        cd $GAR_ROOT
        ;;
    *)
        error_msg "I do not know what you want to do!"
        ;;
esac

Gar 在应用 pandoc 将 Markdown 文档转化为网页时,须要一个 CSS 文件 gar.css,其内容如下:

html {
    font-size: 16px;
    line-height: 1.8rem;
}

body {
    margin: 0 auto;
    max-width: 50rem;
    padding: 50px;
    hyphens: auto;
    word-wrap: break-word;
    font-kerning: normal;
}

header {
    text-align: center;
    margin-bottom: 4rem;
}

h1, h2, h3, h4, h5 {
    margin-top: 2rem;
    margin-bottom: 2rem;
    color: #d35400;
}

h1.title {font-size: 2.5rem;}
h1 {font-size: 1.8rem;}
h2 {font-size: 1.65rem;}
h3 {font-size: 1.5em;}
h4 {font-size: 1.35rem;}
h5 {font-size: 1.2rem;}

p {
    margin: 1.3rem 0;
    text-align: justify;
}

figure {text-align: center;}
figure img {width: 80%;}
figure figcaption {font-size: 0.9rem;}

pre {
    padding: 1rem;
    font-size: 0.9rem;
    line-height: 1.6em;
    overflow:auto;
    background: #f8f8f8;
    border: 1px solid #ccc;
    border-radius: 0.25rem;
}

p code {color: #d35400;}

/* 文章里大节题目的序号与题目名称之间的间距 */
span.section-sep {margin-left: 0.5rem; margin-right: 0.5rem;}


blockquote {
    margin: 0px !important;
    border-left: 4px solid #009A61;
}

blockquote p {
    font-size: 1rem;
    line-height: 1.8rem;
    margin: 0px !important;
    text-align: justify;
    padding:0.5em;
}

上述 gar.css 并无特别之处,齐全可依据本人对 css 的相熟水平并联合须要自行定制,然而要记得将它放在 gar 脚本同一目录下。

正文完
 0