From f3329f0a82cf7b4ef3fa8011f87fc8a3dafd753e Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Sun, 10 Jan 2016 19:31:49 +0100 Subject: [PATCH 1/6] Remove unnecessary quotes from scalar assignments Substitutions (variables, command substitutions, etc.) directly assigned to a scalar variable don't need to be quoted, as field splitting and globbing don't apply in that context. Removing superfluous quotes makes the code look a bit cleaner. --- bb.sh | 140 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/bb.sh b/bb.sh index eacf90b..147cd20 100755 --- a/bb.sh +++ b/bb.sh @@ -143,7 +143,7 @@ global_variables() { # Markdown location. Trying to autodetect by default. # The invocation must support the signature 'markdown_bin in.md > out.html' - markdown_bin="$(which Markdown.pl || which markdown)" + markdown_bin=$(which Markdown.pl || which markdown) } # Check for the validity of some variables @@ -182,8 +182,8 @@ test_markdown() { # Parse a Markdown file into HTML and return the generated file markdown() { - out="$(echo $1 | sed 's/md$/html/g')" - while [ -f "$out" ]; do out="$(echo $out | sed 's/\.html$/\.'$RANDOM'\.html/')"; done + out=$(echo $1 | sed 's/md$/html/g') + while [ -f "$out" ]; do out=$(echo $out | sed 's/\.html$/\.'$RANDOM'\.html/'); done $markdown_bin "$1" > "$out" echo "$out" } @@ -281,12 +281,12 @@ get_html_file_content() { # leave empty for default behavior (edit only text part and change name) edit() { # Original post timestamp - edit_timestamp="$(LC_ALL=C date -r "${1%%.*}.html" +"%a, %d %b %Y %H:%M:%S %z" )" - touch_timestamp="$(LC_ALL=C date -r "${1%%.*}.html" +'%Y%m%d%H%M')" - tags_before="$(tags_in_post "${1%%.*}.html")" + edit_timestamp=$(LC_ALL=C date -r "${1%%.*}.html" +"%a, %d %b %Y %H:%M:%S %z" ) + touch_timestamp=$(LC_ALL=C date -r "${1%%.*}.html" +'%Y%m%d%H%M') + tags_before=$(tags_in_post "${1%%.*}.html") if [ "$2" = "full" ]; then $EDITOR "$1" - filename="$1" + filename=$1 else if [[ "${1##*.}" == "md" ]]; then test_markdown @@ -296,17 +296,17 @@ edit() { fi # editing markdown file $EDITOR "$1" - TMPFILE="$(markdown "$1")" - filename="${1%%.*}.html" + TMPFILE=$(markdown "$1") + filename=${1%%.*}.html else # Create the content file - TMPFILE="$(basename $1).$RANDOM.html" + TMPFILE=$(basename $1).$RANDOM.html # Title echo "$(get_post_title $1)" > "$TMPFILE" # Post text with plaintext tags get_html_file_content 'text' 'text' <$1 | sed "/^

$template_tags_line_header/s|\\1|\\1|g" >> "$TMPFILE" $EDITOR "$TMPFILE" - filename="$1" + filename=$1 fi rm "$filename" if [ "$2" = "keep" ]; then @@ -320,8 +320,8 @@ edit() { touch -t "$touch_timestamp" "$filename" chmod 644 "$filename" echo "Posted $filename" - tags_after="$(tags_in_post $filename)" - relevant_tags="$(echo "$tags_before $tags_after" | tr ',' ' ' | tr ' ' '\n' | sort -u | tr '\n' ' ')" + tags_after=$(tags_in_post $filename) + relevant_tags=$(echo "$tags_before $tags_after" | tr ',' ' ' | tr ' ' '\n' | sort -u | tr '\n' ' ') if [ ! -z "$relevant_tags" ]; then relevant_posts="$(posts_with_tags $relevant_tags) $filename" rebuild_tags "$relevant_posts" "$relevant_tags" @@ -342,7 +342,7 @@ twitter_card() { echo "" image=$(sed -n 's/.*" } @@ -387,7 +387,7 @@ twitter() { # Return 0 (bash return value 'true') if the input file is an index, feed, etc # or 1 (bash return value 'false') if it is a blogpost is_boilerplate_file() { - name="`clean_filename $1`" + name=$(clean_filename $1) if [[ "$name" == "$index_file" ]] || [[ "$name" == "$archive_index" ]] || [[ "$name" == "$tags_index" ]] || [[ "$name" == "$footer_file" ]] || [[ "$name" == "$header_file" ]] || [[ "$name" == "$global_analytics_file" ]] || [[ "$name" = "$prefix_tags"* ]] ; then return 0 else # Check for exclded for excl in ${html_exclude[*]}; do @@ -402,7 +402,7 @@ is_boilerplate_file() { # $1 the file name # returns the clean file name clean_filename() { - name="$1" + name=$1 [[ "${name:0:2}" == "./" ]] && name=${name:2} # Delete leading './' echo $name } @@ -419,11 +419,11 @@ clean_filename() { # $4 title for the html header # $5 original blog timestamp create_html_page() { - content="$1" - filename="$2" - index="$3" - title="$4" - timestamp="$5" + content=$1 + filename=$2 + index=$3 + title=$4 + timestamp=$5 # Create the actual blog post # html, head @@ -443,8 +443,8 @@ create_html_page() { echo '' >> "$filename" # title, header, headerholder echo '

' >> "$filename" - file_url="`clean_filename $filename`" - file_url="$(sed 's/.rebuilt//g' <<< $file_url)" # Get the correct URL when rebuilding + file_url=$(clean_filename $filename) + file_url=$(sed 's/.rebuilt//g' <<< $file_url) # Get the correct URL when rebuilding # one blog entry if [[ "$index" == "no" ]]; then echo '' >> "$filename" # marks the beginning of the whole post @@ -502,22 +502,22 @@ parse_file() { else filename=$title [[ "$convert_filename" ]] && - filename="$(echo $title | eval $convert_filename)" + filename=$(echo $title | eval $convert_filename) [[ "$filename" ]] || filename=$RANDOM # don't allow empty filenames - filename="$filename.html" + filename=$filename.html # Check for duplicate file names while [ -f "$filename" ]; do - suffix="$RANDOM" - filename="$(echo $filename | sed 's/\.html/'$suffix'\.html/g')" + suffix=$RANDOM + filename=$(echo $filename | sed 's/\.html/'$suffix'\.html/g') done fi - content="$filename.tmp" + content=$filename.tmp # Parse possible tags elif [[ "$line" = "

$template_tags_line_header"* ]]; then - tags="$(echo "$line" | cut -d ":" -f 2- | sed -e 's/<\/p>//g' -e 's/^ *//' -e 's/ *$//' -e 's/, /,/g')" + tags=$(echo "$line" | cut -d ":" -f 2- | sed -e 's/<\/p>//g' -e 's/^ *//' -e 's/ *$//' -e 's/, /,/g') IFS=, read -r -a array <<< "$tags" echo -n "

$template_tags_line_header " >> "$content" @@ -538,19 +538,19 @@ parse_file() { # also the drafts write_entry() { test_markdown && fmt="md" || fmt="html" - f="$2" - [[ "$2" == "-html" ]] && fmt="html" && f="$3" + f=$2 + [[ "$2" == "-html" ]] && fmt="html" && f=$3 if [[ "$f" != "" ]]; then - TMPFILE="$f" + TMPFILE=$f if [[ ! -f "$TMPFILE" ]]; then echo "The file doesn't exist" delete_includes exit fi # guess format from TMPFILE - extension="${TMPFILE##*.}" - [[ "$extension" == "md" || "$extension" == "html" ]] && fmt="$extension" + extension=${TMPFILE##*.} + [[ "$extension" == "md" || "$extension" == "html" ]] && fmt=$extension # but let user override it (`bb.sh post -html file.md`) [[ "$2" == "-html" ]] && fmt="html" # Test if Markdown is working before re-posting a .md file @@ -586,7 +586,7 @@ EOF [ "$filename" ] && rm "$filename" # Delete the generated html file, if any $EDITOR "$TMPFILE" if [[ "$fmt" == "md" ]]; then - html_from_md="$(markdown "$TMPFILE")" + html_from_md=$(markdown "$TMPFILE") parse_file "$html_from_md" rm "$html_from_md" else @@ -594,7 +594,7 @@ EOF fi chmod 644 "$filename" - [ "$preview_url" ] || preview_url="$global_url" + [ "$preview_url" ] || preview_url=$global_url echo "To preview the entry, open $preview_url/$filename in your browser" echo -n "[P]ost this entry, [E]dit again, [D]raft for later? (p/E/d) " @@ -603,8 +603,8 @@ EOF mkdir -p "drafts/" chmod 700 "drafts/" - title="$(head -n 1 $TMPFILE)" - [[ "$convert_filename" ]] && title="$(echo $title | eval $convert_filename)" + title=$(head -n 1 $TMPFILE) + [[ "$convert_filename" ]] && title=$(echo $title | eval $convert_filename) [[ "$title" ]] || title=$RANDOM draft="drafts/$title.$fmt" @@ -624,7 +624,7 @@ EOF fi chmod 644 "$filename" echo "Posted $filename" - relevant_tags="$(tags_in_post $filename)" + relevant_tags=$(tags_in_post $filename) if [ ! -z "$relevant_tags" ]; then relevant_posts="$(posts_with_tags $relevant_tags) $filename" rebuild_tags "$relevant_posts" "$relevant_tags" @@ -634,9 +634,9 @@ EOF # Create an index page with all the posts all_posts() { echo -n "Creating an index page with all the posts " - contentfile="$archive_index.$RANDOM" + contentfile=$archive_index.$RANDOM while [ -f "$contentfile" ]; do - contentfile="$archive_index.$RANDOM" + contentfile=$archive_index.$RANDOM done echo "

$template_archive_title

" >> "$contentfile" @@ -645,18 +645,18 @@ all_posts() { is_boilerplate_file "$i" && continue echo -n "." # Month headers - month="$(LC_ALL=$date_locale date -r "$i" +"$date_allposts_header")" + month=$(LC_ALL=$date_locale date -r "$i" +"$date_allposts_header") if [[ "$month" != "$prev_month" ]]; then [[ "$prev_month" ]] && echo "" >> "$contentfile" # Don't close ul before first header echo "

$month

" >> "$contentfile" echo "
    " >> "$contentfile" - prev_month="$month" + prev_month=$month fi # Title - title="$(get_post_title "$i")" + title=$(get_post_title "$i") echo -n '
  • '$title' —' >> "$contentfile" # Date - date="$(LC_ALL=$date_locale date -r "$i" +"$date_format")" + date=$(LC_ALL=$date_locale date -r "$i" +"$date_format") echo " $date
  • " >> "$contentfile" done echo "" @@ -672,18 +672,18 @@ all_posts() { # Create an index page with all the tags all_tags() { echo -n "Creating an index page with all the tags " - contentfile="$tags_index.$RANDOM" + contentfile=$tags_index.$RANDOM while [ -f "$contentfile" ]; do - contentfile="$tags_index.$RANDOM" + contentfile=$tags_index.$RANDOM done echo "

    $template_tags_title

    " >> "$contentfile" echo "
      " >> "$contentfile" for i in $(ls ./$prefix_tags*.html 2>/dev/null || echo ''); do echo -n "." - nposts="$(grep -c "<\!-- text begin -->" $i)" - tagname="$(echo $i | cut -c $((${#prefix_tags}+3))- | sed 's/\.html//g')" - i="`clean_filename $i`" + nposts=$(grep -c "<\!-- text begin -->" $i) + tagname=$(echo $i | cut -c $((${#prefix_tags}+3))- | sed 's/\.html//g') + i=$(clean_filename $i) echo "
    • $tagname — $nposts $template_tags_posts
    • " >> "$contentfile" done echo "" @@ -699,11 +699,11 @@ all_tags() { # Generate the index.html with the content of the latest posts rebuild_index() { echo -n "Rebuilding the index " - newindexfile="$index_file.$RANDOM" - contentfile="$newindexfile.content" + newindexfile=$index_file.$RANDOM + contentfile=$newindexfile.content while [ -f "$newindexfile" ]; do - newindexfile="$index_file.$RANDOM" - contentfile="$newindexfile.content" + newindexfile=$index_file.$RANDOM + contentfile=$newindexfile.content done # Create the content file @@ -720,8 +720,8 @@ rebuild_index() { n=$(( n + 1 )) done - feed="$blog_feed" - if [[ "$global_feedburner" != "" ]]; then feed="$global_feedburner"; fi + feed=$blog_feed + if [[ "$global_feedburner" != "" ]]; then feed=$global_feedburner; fi echo '' >> "$contentfile" echo "" @@ -744,7 +744,7 @@ tags_in_post() { # Prints one line with space-separated tags to stdout posts_with_tags() { [ $# -lt 1 ] && return - tag_files="$(for i in $@; do echo -n $prefix_tags""$i.html" "; done)" + tag_files=$(for i in "$@"; do echo -n $prefix_tags""$i.html" "; done) sed -n '/^

      /{s/.*href="\([^"]*\)">.*/\1/;p;}' $tag_files 2> /dev/null } @@ -760,13 +760,13 @@ posts_with_tags() { rebuild_tags() { if [ "$#" -lt 2 ]; then # will process all files and tags - files="$(ls -t ./*.html)" + files=$(ls -t ./*.html) all_tags="yes" else # will process only given files and tags - files="$(echo "$1" | tr ' ' '\n' | sort -u | tr '\n' ' ')" - files="$(ls -t $files)" - tags="$2" + files=$(echo "$1" | tr ' ' '\n' | sort -u | tr '\n' ' ') + files=$(ls -t $files) + tags=$2 fi echo -n "Rebuilding tag pages " n=0 @@ -782,7 +782,7 @@ rebuild_tags() { for i in $files; do is_boilerplate_file "$i" && continue; echo -n "." - tmpfile="$(mktemp tmp.XXX)" + tmpfile=$(mktemp tmp.XXX) if [ "$cut_do" ]; then get_html_file_content 'entry' 'entry' 'cut' <$i | awk '/'"$cut_line"'/ { print "

      '"$template_read_more"'

      " ; next } 1' >> "$tmpfile" else @@ -797,7 +797,7 @@ rebuild_tags() { done # Now generate the tag files with headers, footers, etc for i in $(ls -t ./$prefix_tags*.tmp.html 2>/dev/null || echo ''); do - tagname="$(echo $i | cut -c $((${#prefix_tags}+3))- | sed 's/\.tmp\.html//g')" + tagname=$(echo $i | cut -c $((${#prefix_tags}+3))- | sed 's/\.tmp\.html//g') create_html_page "$i" "$prefix_tags$tagname.html" yes "$global_title — $template_tag_title \"$tagname\"" rm "$i" done @@ -821,7 +821,7 @@ list_posts() { for i in $(ls -t ./*.html); do is_boilerplate_file "$i" && continue line="$n # $(get_post_title "$i") # $(LC_ALL=$date_locale date -r $i +"$date_format")" - lines="${lines}""$line""\n" # Weird stuff needed for the newlines + lines+=$line\\n n=$(( n + 1 )) done @@ -832,8 +832,8 @@ list_posts() { make_rss() { echo -n "Making RSS " - rssfile="$blog_feed.$RANDOM" - while [ -f "$rssfile" ]; do rssfile="$blog_feed.$RANDOM"; done + rssfile=$blog_feed.$RANDOM + while [ -f "$rssfile" ]; do rssfile=$blog_feed.$RANDOM; done echo '' >> "$rssfile" echo '' >> "$rssfile" @@ -890,7 +890,7 @@ create_includes() { if [[ -f "$footer_file" ]]; then cp "$footer_file" .footer.html else - protected_mail="$(echo "$global_email" | sed 's/@/\@/g' | sed 's/\./\./g')" + protected_mail=$(echo "$global_email" | sed 's/@/\@/g' | sed 's/\./\./g') echo '' >> ".footer.html" fi @@ -959,15 +959,15 @@ rebuild_all_entries() { echo -n "." # Get the title and entry, and rebuild the html structure from scratch (divs, title, description...) - title="$(get_post_title "$i")" + title=$(get_post_title "$i") get_html_file_content 'text' 'text' <$i >> "$contentfile" # Original post timestamp - timestamp="$(LC_ALL=C date -r $i +"%a, %d %b %Y %H:%M:%S %z" )" + timestamp=$(LC_ALL=C date -r $i +"%a, %d %b %Y %H:%M:%S %z" ) create_html_page "$contentfile" "$i.rebuilt" no "$title" "$timestamp" # keep the original timestamp! - timestamp="$(LC_ALL=C date -r $i +'%Y%m%d%H%M')" + timestamp=$(LC_ALL=C date -r $i +'%Y%m%d%H%M') mv "$i.rebuilt" "$i" chmod 644 "$i" touch -t "$timestamp" "$i" From 2b24132f3cdaa01c3dc3dad22c6542dac52f7437 Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Sun, 10 Jan 2016 23:17:48 +0100 Subject: [PATCH 2/6] Consistent use of [[ and (( instead of [ Another minor code cleanup. Within [[ ... ]] and (( ... )) (but not [ ... ]) there is a different shell parsing context in which field splitting (a.k.a. word splitting) and pathname expansion (a.k.a. filename globbing) don't apply, so consistently use '[[' (and '((' for arithmetics) instead of '[' and remove unnecessary quotes. Since '[[ x == y]]' does 'case'-like glob pattern matching on 'y', the quotes to the right of '==' need to be kept for variables or glob characters, except if a glob pattern is wanted. --- bb.sh | 220 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 111 insertions(+), 109 deletions(-) diff --git a/bb.sh b/bb.sh index 147cd20..3cc5656 100755 --- a/bb.sh +++ b/bb.sh @@ -149,10 +149,10 @@ global_variables() { # Check for the validity of some variables # DO NOT EDIT THIS FUNCTION unless you know what you're doing global_variables_check() { - [[ "$header_file" == ".header.html" ]] && + [[ $header_file == .header.html ]] && echo "Please check your configuration. '.header.html' is not a valid value for the setting 'header_file'" && exit - [[ "$footer_file" == ".footer.html" ]] && + [[ $footer_file == .footer.html ]] && echo "Please check your configuration. '.footer.html' is not a valid value for the setting 'footer_file'" && exit } @@ -160,17 +160,17 @@ global_variables_check() { # Test if the markdown script is working correctly test_markdown() { - [[ -z "$markdown_bin" ]] && return 1 - [[ -z "$(which diff)" ]] && return 1 + [[ -z $markdown_bin ]] && return 1 + [[ -z $(which diff) ]] && return 1 - in="/tmp/md-in-${RANDOM}.md" - out="/tmp/md-out-${RANDOM}.html" - good="/tmp/md-good-${RANDOM}.html" + in=/tmp/md-in-${RANDOM}.md + out=/tmp/md-out-${RANDOM}.html + good=/tmp/md-good-${RANDOM}.html echo -e "line 1\n\nline 2" > "$in" echo -e "

      line 1

      \n\n

      line 2

      " > "$good" $markdown_bin $in > $out 2> /dev/null diff $good $out &> /dev/null # output is irrelevant, we'll check $? - if [[ $? -ne 0 ]]; then + if (($? != 0)); then rm -f "$in" "$good" "$out" return 1 fi @@ -183,7 +183,7 @@ test_markdown() { # Parse a Markdown file into HTML and return the generated file markdown() { out=$(echo $1 | sed 's/md$/html/g') - while [ -f "$out" ]; do out=$(echo $out | sed 's/\.html$/\.'$RANDOM'\.html/'); done + while [[ -f $out ]]; do out=$(echo $out | sed 's/\.html$/\.'$RANDOM'\.html/'); done $markdown_bin "$1" > "$out" echo "$out" } @@ -191,9 +191,9 @@ markdown() { # Prints the required google analytics code google_analytics() { - [[ -z "$global_analytics" ]] && [[ -z "$global_analytics_file" ]] && return + [[ -z $global_analytics && -z $global_analytics_file ]] && return - if [[ -z "$global_analytics_file" ]]; then + if [[ -z $global_analytics_file ]]; then echo "' + echo "" return; else echo "

      $template_comments "; @@ -387,7 +387,7 @@ twitter() { # Return 0 (bash return value 'true') if the input file is an index, feed, etc # or 1 (bash return value 'false') if it is a blogpost is_boilerplate_file() { - name=$(clean_filename $1) + name=$(clean_filename "$1") case $name in ( "$index_file" | "$archive_index" | "$tags_index" | "$footer_file" | "$header_file" | "$global_analytics_file" | "$prefix_tags"* ) return 0 ;; @@ -404,9 +404,7 @@ is_boilerplate_file() { # $1 the file name # returns the clean file name clean_filename() { - name=$1 - [[ ${name:0:2} == ./ ]] && name=${name:2} # Delete leading './' - echo $name + echo "${1#./}" # Delete leading './' } # Adds all the bells and whistles to format the html page @@ -429,59 +427,61 @@ create_html_page() { # Create the actual blog post # html, head - cat ".header.html" > "$filename" - echo "$title" >> "$filename" - google_analytics >> "$filename" - twitter_card "$content" "$title" >> "$filename" - echo "" >> "$filename" - # stuff to add before the actual body content - [[ -n $body_begin_file ]] && cat "$body_begin_file" >> "$filename" - # body divs - echo '

      ' >> "$filename" - echo '
      ' >> "$filename" - # blog title - echo '
      ' >> "$filename" - cat .title.html >> "$filename" - echo '
      ' >> "$filename" # title, header, headerholder - echo '
      ' >> "$filename" + { + cat ".header.html" + echo "$title" + google_analytics + twitter_card "$content" "$title" + echo "" + # stuff to add before the actual body content + [[ -n $body_begin_file ]] && cat "$body_begin_file" + # body divs + echo '
      ' + echo '
      ' + # blog title + echo '
      ' + cat .title.html + echo '
      ' # title, header, headerholder + echo '
      ' - file_url=$(clean_filename $filename) - file_url=$(sed 's/.rebuilt//g' <<< $file_url) # Get the correct URL when rebuilding - # one blog entry - if [[ $index == no ]]; then - echo '' >> "$filename" # marks the beginning of the whole post - echo '

      ' >> "$filename" - # remove possible

      's on the title because of markdown conversion - echo "$(echo "$title" | sed 's/<\/*p>//g')" >> "$filename" - echo '

      ' >> "$filename" - if [[ -z $timestamp ]]; then - echo '
      '$(LC_ALL=$date_locale date +"$date_format")' — ' >> "$filename" - else - echo '
      '$(LC_ALL=$date_locale date +"$date_format" --date="$timestamp") ' — ' >> "$filename" + file_url=$(clean_filename "$filename") + file_url=$(sed 's/.rebuilt//g' <<< "$file_url") # Get the correct URL when rebuilding + # one blog entry + if [[ $index == no ]]; then + echo '' # marks the beginning of the whole post + echo "

      " + # remove possible

      's on the title because of markdown conversion + echo "$title" | sed 's/<\/*p>//g' + echo '

      ' + if [[ -z $timestamp ]]; then + echo "
      $(LC_ALL=$date_locale date +"$date_format") — " + else + echo "
      $(LC_ALL=$date_locale date +"$date_format" --date="$timestamp") — " + fi + echo "$global_author
      " + echo '' # This marks the text body, after the title, date... fi - echo "$global_author
      " >> "$filename" - echo '' >> "$filename" # This marks the text body, after the title, date... - fi - cat "$content" >> "$filename" # Actual content - if [[ $index == no ]]; then - echo -e '\n' >> "$filename" + cat "$content" # Actual content + if [[ $index == no ]]; then + echo -e '\n' - twitter "$global_url/$file_url" >> "$filename" + twitter "$global_url/$file_url" - echo '' >> "$filename" # absolute end of the post - fi + echo '' # absolute end of the post + fi - echo '
      ' >> "$filename" # content + echo '
      ' # content - # Add disqus commments except for index and all_posts pages - [[ $index == no ]] && disqus_body >> "$filename" + # Add disqus commments except for index and all_posts pages + [[ $index == no ]] && disqus_body - # page footer - cat .footer.html >> "$filename" - # close divs - echo '
      ' >> "$filename" # divbody and divbodyholder - disqus_footer >> "$filename" - echo '' >> "$filename" + # page footer + cat .footer.html + # close divs + echo '
      ' # divbody and divbodyholder + disqus_footer + echo '' + } > "$filename" } # Parse the plain text file into an html file @@ -504,7 +504,7 @@ parse_file() { else filename=$title [[ -n $convert_filename ]] && - filename=$(echo $title | eval $convert_filename) + filename=$(echo "$title" | eval "$convert_filename") [[ -n $filename ]] || filename=$RANDOM # don't allow empty filenames @@ -512,8 +512,7 @@ parse_file() { # Check for duplicate file names while [[ -f $filename ]]; do - suffix=$RANDOM - filename=$(echo $filename | sed 's/\.html/'$suffix'\.html/g') + filename=${filename%.html}$RANDOM.html done fi content=$filename.tmp @@ -600,13 +599,13 @@ EOF echo "To preview the entry, open $preview_url/$filename in your browser" echo -n "[P]ost this entry, [E]dit again, [D]raft for later? (p/E/d) " - read post_status + read -r post_status if [[ $post_status == d || $post_status == D ]]; then mkdir -p "drafts/" chmod 700 "drafts/" title=$(head -n 1 $TMPFILE) - [[ -n $convert_filename ]] && title=$(echo $title | eval $convert_filename) + [[ -n $convert_filename ]] && title=$(echo "$title" | eval "$convert_filename") [[ -n $title ]] || title=$RANDOM draft=drafts/$title.$fmt @@ -641,29 +640,31 @@ all_posts() { contentfile=$archive_index.$RANDOM done - echo "

      $template_archive_title

      " >> "$contentfile" - prev_month="" - for i in $(ls -t ./*.html); do - is_boilerplate_file "$i" && continue - echo -n "." - # Month headers - month=$(LC_ALL=$date_locale date -r "$i" +"$date_allposts_header") - if [[ $month != "$prev_month" ]]; then - [[ -n $prev_month ]] && echo "

    " >> "$contentfile" # Don't close ul before first header - echo "

    $month

    " >> "$contentfile" - echo "
      " >> "$contentfile" - prev_month=$month - fi - # Title - title=$(get_post_title "$i") - echo -n '
    • '$title' —' >> "$contentfile" - # Date - date=$(LC_ALL=$date_locale date -r "$i" +"$date_format") - echo " $date
    • " >> "$contentfile" - done - echo "" - echo "
    " >> "$contentfile" - echo '' >> "$contentfile" + { + echo "

    $template_archive_title

    " + prev_month="" + for i in $(ls -t ./*.html); do + is_boilerplate_file "$i" && continue + echo -n "." 1>&3 + # Month headers + month=$(LC_ALL=$date_locale date -r "$i" +"$date_allposts_header") + if [[ $month != "$prev_month" ]]; then + [[ -n $prev_month ]] && echo "
" # Don't close ul before first header + echo "

$month

" + echo "
    " + prev_month=$month + fi + # Title + title=$(get_post_title "$i") + echo -n "
  • $title —" + # Date + date=$(LC_ALL=$date_locale date -r "$i" +"$date_format") + echo " $date
  • " + done + echo "" 1>&3 + echo "
" + echo "" + } 3>&1 >"$contentfile" create_html_page "$contentfile" "$archive_index.tmp" yes "$global_title — $template_archive_title" mv "$archive_index.tmp" "$archive_index" @@ -679,18 +680,21 @@ all_tags() { contentfile=$tags_index.$RANDOM done - echo "

$template_tags_title

" >> "$contentfile" - echo "
    " >> "$contentfile" - for i in $(ls ./$prefix_tags*.html 2>/dev/null || echo ''); do - echo -n "." - nposts=$(grep -c "<\!-- text begin -->" $i) - tagname=$(echo $i | cut -c $((${#prefix_tags}+3))- | sed 's/\.html//g') - i=$(clean_filename $i) - echo "
  • $tagname — $nposts $template_tags_posts
  • " >> "$contentfile" - done - echo "" - echo "
" >> "$contentfile" - echo '' >> "$contentfile" + { + echo "

$template_tags_title

" + echo "
    " + for i in ./$prefix_tags*.html; do + [[ -f "$i" ]] || break + echo -n "." 1>&3 + nposts=$(grep -c "<\!-- text begin -->" "$i") + tagname=$(echo "$i" | cut -c "$((${#prefix_tags}+3))-" | sed 's/\.html//g') + i=$(clean_filename "$i") + echo "
  • $tagname — $nposts $template_tags_posts
  • " + done + echo "" 1>&3 + echo "
" + echo "" + } 3>&1 > "$contentfile" create_html_page "$contentfile" "$tags_index.tmp" yes "$global_title — $template_tags_title" mv "$tags_index.tmp" "$tags_index" @@ -709,22 +713,24 @@ rebuild_index() { done # Create the content file - n=0 - for i in $(ls -t ./*.html); do # sort by date, newest first - is_boilerplate_file "$i" && continue; - if ((n >= number_of_index_articles)); then break; fi - if [[ -n $cut_do ]]; then - get_html_file_content 'entry' 'entry' 'cut' <$i | awk '/'"$cut_line"'/ { print "

'"$template_read_more"'

" ; next } 1' >> "$contentfile" - else - get_html_file_content 'entry' 'entry' <$i >> "$contentfile" - fi - echo -n "." - n=$(( n + 1 )) - done + { + n=0 + for i in $(ls -t ./*.html); do # sort by date, newest first + is_boilerplate_file "$i" && continue; + if ((n >= number_of_index_articles)); then break; fi + if [[ -n $cut_do ]]; then + get_html_file_content 'entry' 'entry' 'cut' <"$i" | awk "/$cut_line/ { print \"

$template_read_more

\" ; next } 1" + else + get_html_file_content 'entry' 'entry' <"$i" + fi + echo -n "." 1>&3 + n=$(( n + 1 )) + done - feed=$blog_feed - if [[ -n $global_feedburner ]]; then feed=$global_feedburner; fi - echo '' >> "$contentfile" + feed=$blog_feed + if [[ -n $global_feedburner ]]; then feed=$global_feedburner; fi + echo "" + } 3>&1 >"$contentfile" echo "" @@ -774,10 +780,10 @@ rebuild_tags() { echo -n "Rebuilding tag pages " n=0 if [[ -n $all_tags ]]; then - rm ./$prefix_tags*.html &> /dev/null + rm ./"$prefix_tags"*.html &> /dev/null else for i in $tags; do - rm ./$prefix_tags$i.html &> /dev/null + rm "./$prefix_tags$i.html" &> /dev/null done fi # First we will process all files and create temporal tag files @@ -787,11 +793,11 @@ rebuild_tags() { echo -n "." tmpfile=$(mktemp tmp.XXX) if [[ -n $cut_do ]]; then - get_html_file_content 'entry' 'entry' 'cut' <$i | awk '/'"$cut_line"'/ { print "

'"$template_read_more"'

" ; next } 1' >> "$tmpfile" + get_html_file_content 'entry' 'entry' 'cut' <"$i" | awk "/$cut_line/ { print \"

$template_read_more

\" ; next } 1" else - get_html_file_content 'entry' 'entry' <$i >> "$tmpfile" - fi - for tag in $(tags_in_post $i); do + get_html_file_content 'entry' 'entry' <"$i" + fi >"$tmpfile" + for tag in $(tags_in_post "$i"); do if [[ -n $all_tags || " $tags " == *" $tag "* ]]; then cat "$tmpfile" >> "$prefix_tags$tag".tmp.html fi @@ -800,7 +806,7 @@ rebuild_tags() { done # Now generate the tag files with headers, footers, etc for i in $(ls -t ./$prefix_tags*.tmp.html 2>/dev/null || echo ''); do - tagname=$(echo $i | cut -c $((${#prefix_tags}+3))- | sed 's/\.tmp\.html//g') + tagname=$(echo "$i" | cut -c "$((${#prefix_tags}+3))-" | sed 's/\.tmp\.html//g') create_html_page "$i" "$prefix_tags$tagname.html" yes "$global_title — $template_tag_title \"$tagname\"" rm "$i" done @@ -823,7 +829,7 @@ list_posts() { n=1 for i in $(ls -t ./*.html); do is_boilerplate_file "$i" && continue - line="$n # $(get_post_title "$i") # $(LC_ALL=$date_locale date -r $i +"$date_format")" + line="$n # $(get_post_title "$i") # $(LC_ALL=$date_locale date -r "$i" +"$date_format")" lines+=$line\\n n=$(( n + 1 )) done @@ -838,32 +844,35 @@ make_rss() { rssfile=$blog_feed.$RANDOM while [[ -f $rssfile ]]; do rssfile=$blog_feed.$RANDOM; done - echo '' >> "$rssfile" - echo '' >> "$rssfile" - echo ''$global_title''$global_url'' >> "$rssfile" - echo ''$global_description'en' >> "$rssfile" - echo ''$(LC_ALL=C date +"%a, %d %b %Y %H:%M:%S %z")'' >> "$rssfile" - echo ''$(LC_ALL=C date +"%a, %d %b %Y %H:%M:%S %z")'' >> "$rssfile" - echo '' >> "$rssfile" - - n=0 - for i in $(ls -t ./*.html); do - is_boilerplate_file "$i" && continue - ((n >= number_of_feed_articles)) && break # max 10 items - echo -n "." - echo '' >> "$rssfile" - echo "$(get_post_title "$i")" >> "$rssfile" - echo '> "$rssfile" - echo "$(get_html_file_content 'text' 'entry' $cut_do <$i)" >> "$rssfile" - echo "]]>$global_url/$(clean_filename $i)" >> "$rssfile" - echo "$global_url/$i" >> "$rssfile" - echo "$global_author" >> "$rssfile" - echo ''$(LC_ALL=C date -r "$i" +"%a, %d %b %Y %H:%M:%S %z")'' >> "$rssfile" - - n=$(( n + 1 )) - done - - echo '' >> "$rssfile" + { + pubdate=$(LC_ALL=C date +"%a, %d %b %Y %H:%M:%S %z") + echo '' + echo '' + echo "$global_title$global_url" + echo "$global_descriptionen" + echo "$pubdate" + echo "$pubdate" + echo "" + + n=0 + for i in $(ls -t ./*.html); do + is_boilerplate_file "$i" && continue + ((n >= number_of_feed_articles)) && break # max 10 items + echo -n "." 1>&3 + echo '' + get_post_title "$i" + echo '$global_url/$(clean_filename "$i")" + echo "$global_url/$i" + echo "$global_author" + echo "$(LC_ALL=C date -r "$i" +"%a, %d %b %Y %H:%M:%S %z")" + + n=$(( n + 1 )) + done + + echo '' + } 3>&1 >"$rssfile" echo "" mv "$rssfile" "$blog_feed" @@ -872,28 +881,33 @@ make_rss() { # generate headers, footers, etc create_includes() { - echo '

'$global_title'

' > ".title.html" - echo '
'$global_description'
' >> ".title.html" + { + echo "

$global_title

" + echo "
$global_description
" + } > ".title.html" if [[ -f $header_file ]]; then cp "$header_file" .header.html - else - echo '' > ".header.html" - echo '' >> ".header.html" - echo '' >> ".header.html" - echo '' >> ".header.html" - printf '\n' "${css_include[@]}" >> ".header.html" + else { + echo '' + echo '' + echo '' + echo '' + printf '\n' "${css_include[@]}" if [[ -z $global_feedburner ]]; then - echo '' >> ".header.html" + echo "" else - echo '' >> ".header.html" + echo "" fi + } > ".header.html" fi if [[ -f $footer_file ]]; then cp "$footer_file" .footer.html - else - protected_mail=$(echo "$global_email" | sed 's/@/\@/g' | sed 's/\./\./g') - echo '' >> ".footer.html" + else { + protected_mail=${global_email//@/@} + protected_mail=${protected_mail//./.} + echo "
$global_license $global_author$protected_mail
" + echo 'Generated with bashblog, a single bash script to easily create blogs like this one
' + } >> ".footer.html" fi } @@ -961,14 +975,14 @@ rebuild_all_entries() { echo -n "." # Get the title and entry, and rebuild the html structure from scratch (divs, title, description...) title=$(get_post_title "$i") - get_html_file_content 'text' 'text' <$i >> "$contentfile" + get_html_file_content 'text' 'text' <"$i" >> "$contentfile" # Original post timestamp - timestamp=$(LC_ALL=C date -r $i +"%a, %d %b %Y %H:%M:%S %z" ) + timestamp=$(LC_ALL=C date -r "$i" +"%a, %d %b %Y %H:%M:%S %z" ) create_html_page "$contentfile" "$i.rebuilt" no "$title" "$timestamp" # keep the original timestamp! - timestamp=$(LC_ALL=C date -r $i +'%Y%m%d%H%M') + timestamp=$(LC_ALL=C date -r "$i" +'%Y%m%d%H%M') mv "$i.rebuilt" "$i" chmod 644 "$i" touch -t "$timestamp" "$i" @@ -1026,11 +1040,11 @@ date_version_detect() { date() { if [[ $1 == -r ]]; then # Fall back to using stat for 'date -r' - format=$(echo $3 | sed 's/\+//g') + format=${3//+/} stat -f "%Sm" -t "$format" "$2" - elif [[ $* == *--date* ]]; then + elif [[ $2 == --date* ]]; then # convert between dates using BSD date syntax - command date -j -f "%a, %d %b %Y %H:%M:%S %z" "$(echo $2 | sed 's/\-\-date\=//g')" "$1" + command date -j -f "%a, %d %b %Y %H:%M:%S %z" "${2#--date=}" "$1" else # acceptable format for BSD date command date -j "$@" From b3b0545c7f1dd12ae203a8221d20a911803324d7 Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Mon, 11 Jan 2016 16:10:17 +0100 Subject: [PATCH 5/6] more robust parsing of 'ls' using 'read' * Iterating through 'ls' output using 'for' is very brittle; it relies on word splitting and globbing can also mess it up. It's best to use globs directly, but if using 'ls' cannot be avoided, e.g. if you need to sort by date, at least we can use 'IFS= read -r $i' to read from a here-document filled with the 'ls' output, which leaves everything in file names intact except newlines. * Other minor cleanups. --- bb.sh | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/bb.sh b/bb.sh index c071ea2..7c983b7 100755 --- a/bb.sh +++ b/bb.sh @@ -643,7 +643,7 @@ all_posts() { { echo "

$template_archive_title

" prev_month="" - for i in $(ls -t ./*.html); do + while IFS='' read -r i; do is_boilerplate_file "$i" && continue echo -n "." 1>&3 # Month headers @@ -660,7 +660,7 @@ all_posts() { # Date date=$(LC_ALL=$date_locale date -r "$i" +"$date_format") echo " $date" - done + done < <(ls -t ./*.html) echo "" 1>&3 echo "" echo "" @@ -715,7 +715,7 @@ rebuild_index() { # Create the content file { n=0 - for i in $(ls -t ./*.html); do # sort by date, newest first + while IFS='' read -r i; do is_boilerplate_file "$i" && continue; if ((n >= number_of_index_articles)); then break; fi if [[ -n $cut_do ]]; then @@ -725,7 +725,7 @@ rebuild_index() { fi echo -n "." 1>&3 n=$(( n + 1 )) - done + done < <(ls -t ./*.html) # sort by date, newest first feed=$blog_feed if [[ -n $global_feedburner ]]; then feed=$global_feedburner; fi @@ -773,7 +773,7 @@ rebuild_tags() { all_tags=yes else # will process only given files and tags - files=$(echo "$1" | tr ' ' '\n' | sort -u | tr '\n' ' ') + files=$(printf '%s\n' $1 | sort -u) files=$(ls -t $files) tags=$2 fi @@ -788,10 +788,11 @@ rebuild_tags() { fi # First we will process all files and create temporal tag files # with just the content of the posts - for i in $files; do + tmpfile=tmp.$RANDOM + while [[ -f $tmpfile ]]; do tmpfile=tmp.$RANDOM; done + while IFS='' read -r i; do is_boilerplate_file "$i" && continue; echo -n "." - tmpfile=$(mktemp tmp.XXX) if [[ -n $cut_do ]]; then get_html_file_content 'entry' 'entry' 'cut' <"$i" | awk "/$cut_line/ { print \"

$template_read_more

\" ; next } 1" else @@ -802,14 +803,14 @@ rebuild_tags() { cat "$tmpfile" >> "$prefix_tags$tag".tmp.html fi done - rm "$tmpfile" - done + done <<< "$files" + rm "$tmpfile" # Now generate the tag files with headers, footers, etc - for i in $(ls -t ./$prefix_tags*.tmp.html 2>/dev/null || echo ''); do + while IFS='' read -r i; do tagname=$(echo "$i" | cut -c "$((${#prefix_tags}+3))-" | sed 's/\.tmp\.html//g') create_html_page "$i" "$prefix_tags$tagname.html" yes "$global_title — $template_tag_title \"$tagname\"" rm "$i" - done + done < <(ls -t ./"$prefix_tags"*.tmp.html 2>/dev/null) echo } @@ -827,12 +828,12 @@ list_posts() { lines="" n=1 - for i in $(ls -t ./*.html); do + while IFS='' read -r i; do is_boilerplate_file "$i" && continue line="$n # $(get_post_title "$i") # $(LC_ALL=$date_locale date -r "$i" +"$date_format")" lines+=$line\\n n=$(( n + 1 )) - done + done < <(ls -t ./*.html) echo -e "$lines" | column -t -s "#" } @@ -855,7 +856,7 @@ make_rss() { echo "" n=0 - for i in $(ls -t ./*.html); do + while IFS='' read -r i; do is_boilerplate_file "$i" && continue ((n >= number_of_feed_articles)) && break # max 10 items echo -n "." 1>&3 @@ -869,7 +870,7 @@ make_rss() { echo "$(LC_ALL=C date -r "$i" +"%a, %d %b %Y %H:%M:%S %z")" n=$(( n + 1 )) - done + done < <(ls -t ./*.html) echo '' } 3>&1 >"$rssfile" @@ -1086,18 +1087,17 @@ do_main() { fi # Test for existing html files - ls ./*.html &> /dev/null - (($? != 0)) && [[ $1 == rebuild ]] && - echo "Can't find any html files, nothing to rebuild" && exit - - # We're going to back up just in case - ls ./*.html &> /dev/null - (($? == 0)) && + if ls ./*.html &> /dev/null; then + # We're going to back up just in case tar cfz ".backup.tar.gz" *.html && - chmod 600 ".backup.tar.gz" + chmod 600 ".backup.tar.gz" + elif [[ $1 == rebuild ]]; then + echo "Can't find any html files, nothing to rebuild" + exit + fi # Keep first backup of this day containing yesterday's version of the blog - [[ ! -f .yesterday.tar.gz || $(LC_ALL=$date_locale date -r .yesterday.tar.gz +'%d') != "$(LC_ALL=$date_locale date +'%d')" ]] && + [[ ! -f .yesterday.tar.gz || $(date -r .yesterday.tar.gz +'%d') != "$(date +'%d')" ]] && cp .backup.tar.gz .yesterday.tar.gz &> /dev/null [[ $1 == reset ]] && From 18d2df26ce54c96cb0c95a16b8cf7b5da65e2c5e Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Mon, 11 Jan 2016 18:56:39 +0100 Subject: [PATCH 6/6] fix: allow field splitting on tags_with_posts call Quoted one too many there. --- bb.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bb.sh b/bb.sh index 7c983b7..dbeb198 100755 --- a/bb.sh +++ b/bb.sh @@ -323,7 +323,7 @@ edit() { tags_after=$(tags_in_post "$filename") relevant_tags=$(echo "$tags_before $tags_after" | tr ',' ' ' | tr ' ' '\n' | sort -u | tr '\n' ' ') if [[ ! -z $relevant_tags ]]; then - relevant_posts="$(posts_with_tags "$relevant_tags") $filename" + relevant_posts="$(posts_with_tags $relevant_tags) $filename" rebuild_tags "$relevant_posts" "$relevant_tags" fi }