Auto generate file name based on title?

Hi all,

Has anyone come up with a way to auto-generate the file name based on the title provided for a new post from the command line.

Currently this works:

hugo new posts/my_new_post.md

Then I type the title in the file as My New Post.

Normally I would already have the title in my mind and I do not care what the file name is.

Has someone set an alias or bash function (let’s say hugo_) that on doing,

hugo_ My New Post

auto-creates the posts/my_new_post.md and sets the title in post front-matter to My New Post?

I have come up with this wrapper bash script:

Can something like this be integrated in the hugo binary itself?

#!/usr/bin/env bash
# Time-stamp: <2016-11-28 16:31:04 kmodi>
# https://discuss.gohugo.io/t/auto-generate-file-name-based-on-title/4648/2?u=kaushalmodi

h="
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                                                                                 β”‚
β”‚ Script        : hugo_new_post.sh                                                β”‚
β”‚ Description   : Script to generate a hugo post file using the title specified   β”‚
β”‚                 at the command line.                                            β”‚
β”‚ Usage Example : hugo_new_post.sh -b \"/home/$USER/hugo/myblog\" -t \"My New Post\"  β”‚
β”‚                                                                                 β”‚
β”‚                                                                                 β”‚
β”‚ OPTIONS                                                                         β”‚
β”‚                                                                                 β”‚
β”‚   -b|--blogpath <path> : Root of hugo blog. (Mandatory argument)                β”‚
β”‚                           --blogpath \"/home/\$USER/hugo/myblog\"                  β”‚
β”‚                                                                                 β”‚
β”‚   -t|--title <string>  : Title string of the post. (Mandatory argument)         β”‚
|                          Use double quotes if the title contains spaces.        β”‚
β”‚                           --title \"My New Post\"                                 β”‚
β”‚                                                                                 β”‚
β”‚   -s|--section <dir>    : Sub-directory in the 'content/' dir where the post    β”‚
β”‚                          should be created. (Default: posts)                    β”‚
β”‚                           --section \"blog\"                                      β”‚
β”‚                                                                                 β”‚
β”‚                                                                                 β”‚
β”‚   -h|--help            : Show this help                                         β”‚
β”‚   -d|--debug           : Debug mode                                             β”‚
β”‚                                                                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜"

blog_path=""
section="posts"
title=""
extra_args=""
here=$(pwd)
fext=".md"

debug=0
help=0

while [ $# -gt 0 ]
do
    case "$1" in
        "-b"|"--blogpath" ) shift
                            blog_path="$1";;
        "-t"|"--title" ) shift
                         title="$1";;
        "-s"|"--section" ) shift
                           section="$1";;
        "-d"|"--debug" ) debug=1;;
        "-h"|"--help" ) help=1;;
        * ) extra_args="${extra_args} $1";;
    esac
    shift # expose next argument
done

if [[ ${debug} -eq 1 ]]
then
    echo "blog path  = ${blog_path}"
    echo "title      = ${title}"
    echo "sub dir    = ${section}"
    echo "extra args = ${extra_args}"
fi

main () {
    # Remove leading and trailing whitespace from ${title}
    title=$(echo "${title}" | \sed -r -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')

    # Using ${title}
    #  - Replace '&' with "and", and '.' with "dot".
    #  - Then lower-case the whole title.
    #  - Then replace all characters except a-z, 0-9 and '-' with spaces.
    #  - Then remove leading/trailing spaces if any.
    #  - Then replace one or more spaces with a single hyphen.
    # For example, converts "This, That \& Other!" to "this-that-and-other.md"
    # (Note that we need to escape & with \ above, in the shell.)
    fname=$(echo "${title}" \
                | \sed -r -e 's/&/ and /g' \
                       -e 's/\./ dot /g' \
                       -e 's/./\L\0/g' \
                       -e 's/[^a-z0-9-]/ /g' \
                       -e 's/^[[:space:]]*//g' \
                       -e 's/[[:space:]]*$//g' \
                       -e 's/[[:space:]]+/-/g');
    fpath="${blog_path}/content/${section}/${fname}${fext}"

    if [[ ${debug} -eq 1 ]]
    then
        echo "fname      = ${fname}"
        echo "fpath      = ${fpath}"
    fi

    # Create the new post
    # Need to first cd to the hugo blog root dir
    cd ${blog_path}
    hugo new ${section}/${fname}${fext} ${extra_args}

    # Replace the title in TOML front matter with ${title}, and add slug
    tmp_file="/tmp/${USER}_hugo_post"
    \cp -f ${fpath} ${tmp_file}
    \sed -r -e 's/^(\s*title = ).*/\1"'"${title}"'"/' \
         -e 's/^(\s*title = .*)/\1\nslug = "'"${fname}"'"/' \
         ${tmp_file} > ${fpath}
    \rm -f ${tmp_file}

    # Go back to the directory from where you launched this script
    cd ${here}

    # Open the file in EDITOR with cursor placed on the last line
    last_line=$(wc -l ${fpath} | awk '{ print $1 }')
    open_file_cmd="${EDITOR} +${last_line} ${fpath} &"
    if [[ ${debug} -eq 1 ]]
    then
        echo "last line     = ${last_line}"
        echo "open file cmd = ${open_file_cmd}"
    fi
    eval "${open_file_cmd}"
}

help () {
    echo "${h}"
}

if [[ ${help} -eq 1 ]]
then
    help
    exit 0
elif [[ -z ${blog_path} || -z ${title} ]]
then
    echo "Error: Both '-b' and '-t' are mandatory arguments"
    help
    exit 1
else
    main
    exit 0
fi

UPDATE 2016/11/27: Replaced _ with - in the tr command.
UPDATE 2016/11/28: More improvements to the title->fname derivation. Also add slug to front-matter that matches the fname.

Hi. Have you tried dashes instead of underscores? I run

$ hugo new post/testing-me.md
SITE_ROOT/content/post/testing-me.md created

That file contains

+++
date = "2016-11-27T16:57:06-06:00"
title = "testing me"
+++

I just opened an issue to implement something like this.

https://github.com/spf13/hugo/issues/2743

Thanks. Actually I used underscores by mistake. Since then, I had switched to using hyphens instead. But the issue still remains.

  • I would like the file names to be all lower case and the casing in title to be exactly as i want… example: Now I Know My ABCs :slightly_smiling:

So by me specifying the title at the command line, it’s very easy to lower-case and hyphen-separate everything.

In addition, the script adds minor convenience like,

  • Execution from anywhere (not needing to be in the hugo project root dir)
  • Now having to specify the posts/ subdir each time
  • Opening in my $EDITOR on the last line

On top of that, I have an alias newp. So I can type this from anywhere:

newp My New Post

and that creates posts/my-new-post.md with title My New Post, and opens the file with cursor at the last line in my $EDITOR.

Having the β€œnew post” utility automatically fill out the title is nice, but I’d also like to see hugo simply fall back on inferring a title from the filename if none was provided. This would facilitate import / migration from Jekyll, and would allow users to exploit this content-oriented approach to specifying the title even if they are creating a new post without using the β€œnew post” utility function.

1 Like