Never been to CodeSnippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world (or not, you can keep them private!)

Debugging a file name with a backslash character in Bash

# create a file name containing a backslash character \
file=${HOME}/Desktop/'te:st\file'.txt
echo "${file}"
echo "${file}" | sed -n -e 'l'

echo 'This is a test case for a file name containing a backslash \ character!' > "${file}"
open -e "${file}"

set -vx

# note: avoid trailing spaces in ed commands
cat <<EOF | /bin/ed -s "${file}"
H
,g|^This|s|test case|SUCCESSFUL TEST CASE|
w
EOF

open -e "${file}"


# escape backslashes
cat <<EOF | /bin/ed -s "${file//\\/\\\\}"
H
,g|^This|s|test case|SUCCESSFUL TEST CASE|
w
EOF

open -e "${file}"


# printf "%q"
help printf | sed -E "s/(%q)/$(printf '\e[1m\\1\e[m')/"
echo "${file}"
echo "$(printf "%q" "${file}")"   # cf. help printf
echo "$(printf "%q" "${file}")" | sed -n -e 'l'

# escape file name
cat <<EOF | /bin/ed -s "$(printf "%q" "${file}")"
H
,g|^This|s|backslash|BACKSLASH|
w
EOF

open -e "${file}"


echo "${file}"
echo "${file}" | sed -n -e 'l'

file="${file//\\/\\\\}"
echo "${file}"
echo "${file}" | sed -n -e 'l'


# references
man bash 2>/dev/null | less -p 'backslash'
man bash 2>/dev/null | less -p 'Each command in a pipeline'
man bash 2>/dev/null | less -p 'Functions are executed'
help printf | sed -E "s/(%q)/$(printf '\e[1m\\1\e[m')/"
open http://en.wikipedia.org/wiki/Filename


# "Each command in a pipeline is executed as a separate process (i.e., in a subshell)."
# From: man bash

# "Functions are executed in the context of the current shell; no new process is created to 
# interpret  them (contrast this with the execution of a shell script)."
# From: man bash

# "Unix-like systems are an exception, as the only control character forbidden in file names 
# is the null character, as that's the end-of-string indicator in C. Trivially, Unix also 
# excludes the path separator / from appearing in filenames."
# From: http://en.wikipedia.org/wiki/Filename

Batch download code snippets

Batch download snippets from http://codesnippets.joyent.com and convert them to text files using man textutil (available on Mac OS X 10.4 or later).

Note: Old snippet versions will be automatically replaced by the downloaded snippets without a backup!

Author: jv
License: The MIT License, Copyright (c) 2008 jv

Usage:
# usage: bds [-p num] [-t tag] [-u user] tag
bds vim
bds -p 1280
bds -u jvs
bds -t plistbuddy
bds -t tar
bds -t ipfw -u jvs



#!/opt/local/bin/bash

# "batch download snippets" from http://codesnippets.joyent.com and
# convert them to text files using man textutil (available on Mac OS X 10.4 or later).
#
# Note: Old snippet versions will be automatically replaced by the downloaded snippets without a backup!
#      An alternative to man textutil is html2text, http://www.mbayer.de/html2text/ (which is available via MacPorts).
#
# Author: jv
# License: The MIT License, http://www.opensource.org/licenses/mit-license.php
# Copyright (c) 2008 jv
#
# cat /usr/local/bin/bds
#
# usage: bds [-p num] [-t tag] [-u user] tag


declare BaseURL='http://codesnippets.joyent.com'
declare download_dir="${HOME}/Desktop/Snippets"

# make sure there is no trailing slash
BaseURL="${BaseURL%/}"
download_dir="${download_dir%/}"

declare BasePostURL="${BaseURL}/posts/show"
declare BaseTagURL="${BaseURL}/tag"
declare BaseUserURL="${BaseURL}/user"

# make sure there is no trailing slash
BasePostURL="${BasePostURL%/}"
BaseTagURL="${BaseTagURL%/}"
BaseUserURL="${BaseUserURL%/}"


# man textutil
declare InputEncoding='utf-8'
declare OutputEncoding='utf-8'

export IFS=$' \t\n'


# function to download a single post specified by a post number: bds -p num
# cf. snippet, http://codesnippets.joyent.com/posts/show/1282

function snippet() {

   declare NL OPWD file outputfile postnum title url

   if [[ "${1//[[:digit:]]/}" != "" ]]; then echo "Argument error. No positive integer: ${1}"; return 1; fi

   postnum="${1}"
   url="${BasePostURL}/${postnum}"
   download_dir="${download_dir}/single-downloads"
   /bin/mkdir -p "${download_dir}"
   OPWD="${PWD}"
   cd "${download_dir}"
   /usr/bin/curl -L -O -s --max-time 25 "${url}" || exit 1    # download snippet web page
   file="${download_dir}/${url##*/}"
   trap '/bin/rm -f "${file}"; exit 0' 0 1 2 13 15

   # get title of downloaded web page
   #title="$(/usr/bin/sed -E -n -e '/<[tT][iI][tT][lL][eE]>/{s/^.*<[tT][iI][tT][lL][eE]>(.*)<\/[tT][iI][tT][lL][eE]>.*$/\1/p;q;}' "${file}" | \
   #         /usr/bin/sed -E -e 's/\[[^][:space:]]*\]//g')"    # delete [xxx] tag elements of title

   title="$(/usr/bin/egrep -m 1 -io '<title>.*</title>' "${file}" | /usr/bin/sed -E -e 's/^<title>[[:space:]]*|[[:space:]]*<\/title>$//g' \
             -e 's/\[[^][:space:]]*\]//g')"    # delete [xxx] tag elements of title


   title="${title//CodeSnippets:/}"
   title="${title//\//:}"
   title="${title// /_}"
   title="${title//[[:cntrl:]]/}"
   title="${title%"${title##*[!_]}"}"   # remove trailing underscores

   if [[ $title == '_CodeDrive_Snippets_courtesy_of_Peter_Coopers_handy_little_app' ]] || [[ -z "$title" ]]; then
      printf "\e[0K\e[31m%s\e[0m:  %s\n" "couldn't access" "${url}"
      /bin/rm "${file}"
      return 1
   fi

   outputfile="${download_dir}/${postnum}_${title}.txt"
   #outputfile="${download_dir}/${title}.txt"  # without post number prefix
   #outputfile="${outputfile//__/_}"  # uniq underscores

   printf "\n\e[0K\e[1;30m%s\e[0m:  %s\n\n" "saved as" "${outputfile}"

   /usr/bin/textutil -output "${outputfile}" -convert txt -inputencoding "${InputEncoding}" -encoding "${OutputEncoding}" "${file}"
   /bin/rm "${file}"

   # escape backslashes
   # man bash 2>/dev/null | less -p 'Each command in a pipeline'
   #outputfile="$(printf "%q" "${outputfile}")"  # cf. help printf
   outputfile="${outputfile//\\/\\\\}"

   NL=$'\\\n'

cat <<EOF | /bin/ed -s "${outputfile}"
H
,g/Snippets is a public source code repository/1,/Snippets is a public source code repository/d
,g/You need to create an account or log in to post comments to this site//You need to create an account or log in to post comments to this site/,\$d
,g|(See related posts)$|s|.See related posts.|${NL}${NL}|
,g|^to.* by.* on .*[[:digit:]]$|s|^to\(.*\) by\(.*\) on \(.*[[:digit:]]\)$|${NL}${NL}Author:\2${NL}Date: \3${NL}URL: ${url}${NL}Tags:\1${NL}|
,g|^Comments on this post$|s|\(Comments on this post\)|${NL}\1:|
,g| posts on .* at |s|\(.* posts on .* at .*\)|${NL}\1:|
w
EOF

# additional ed commands
# delete line numbers
# ,g|^[[:space:]]*[[:digit:]]\{1,\}[[:space:]]\{1,3\}|s|^[[:space:]]*[[:digit:]]\{1,\}[[:space:]]\{1,3\}\(.*\)$|\1|
# delete range of lines
# 4,11d


   cd "${OPWD}"
   return 0

}



#----------------------------------------- end of function snippet



declare pflag tflag uflag
declare cnt count dir_name file no_posts_check NL OPWD outputfile postnum tagsite title url urls website 

if [[ $# -eq 0 ]]; then 
   printf "%s\n%s\n" 'No arguments given!' "Usage: ${0##*/} [-p num] [-t tag] [-u user] tag" 1>&2
   exit 1
fi


while getopts ":p:t:u:" option
do
  case $option in
    p) pflag="$OPTARG" ;;
    t) tflag="$OPTARG" ;;
    u) uflag="$OPTARG" ;;
    [?]) printf "%s\n%s\n" 'Argument error!' "Usage: ${0##*/} [-p num] [-t tag] [-u user] tag" 1>&2; exit 1;;
    *) ;;
  esac
done

shift $(($OPTIND - 1))


if [[ $# -eq 1 ]]; then

   dir_name="${1}"
   tagsite="${BaseTagURL}/${1}"

elif [[ $# -gt 1 ]]; then

   printf "%s\n%s\n" 'Too many arguments!' "Usage: ${0##*/} [-p num] [-t tag] [-u user] tag" 1>&2
   exit 1

elif [[ -n "${pflag}" ]]; then
   snippet "${pflag}"
   exit 0

elif [[ -n "${tflag}" ]] && [[ -n "${uflag}" ]]; then

   dir_name="${tflag}-${uflag}"
   tagsite="${BaseUserURL}/${uflag}/tag/${tflag}"

elif [[ -n "${tflag}" ]]; then

   dir_name="${tflag}"
   tagsite="${BaseTagURL}/${tflag}"

elif [[ -n "${uflag}" ]]; then

   dir_name="${uflag}"
   tagsite="${BaseUserURL}/${uflag}"

else

   printf "%s\n%s\n" 'Argument error!' "Usage: ${0##*/} [-p num] [-t tag] [-u user] tag" 1>&2
   exit 1

fi


tagsite="${tagsite%/}"

#echo $dir_name
#echo $tagsite

count=1
cnt=0
curl_max_time=20
website=''
no_posts_check=''
NL=$'\\\n'
download_dir="${download_dir}/${dir_name//\//:}"
download_dir="${download_dir%/}"
/bin/mkdir -p "${download_dir}"
OPWD="${PWD}"
cd "${download_dir}"

# print download directory
printf "\n\e[0K\e[1;30m%s\e[0m:  %s\n\n" "download directory" "${download_dir}"


while [[ -z "${no_posts_check}" ]]; do

   # download website of the form: 
   # http://somewebsite.com/tag/bash/1,
   # http://somewebsite.com/user/name/1 or 
   # http://somewebsite.com/user/name/tag/bash/1

   website="$(/usr/bin/curl -L -s --max-time $curl_max_time "${tagsite}/${count}" )"

   if [[ $? -ne 0 ]]; then 
      printf "\e[0K\e[31m%s\e[0m:  %s\n" "curl_max_time ${curl_max_time}" "${tagsite}/${count}"
      exit 1
   fi

   #if [[ -n "$(printf "%s" "${website}" | /usr/bin/egrep -o 'Application error \(Apache\)')" ]]; then 
      #no_posts_check='Application error (Apache)'
      #printf "\e[0K\e[31m%s\e[0m:  %s\n" "no further posts" "${no_posts_check}"
   #fi

   if [[ -n "$(printf "%s" "${website}" | /usr/bin/egrep -o '>No posts<')" ]]; then 
      no_posts_check='>No posts<'
      #printf "\e[0K\e[31m%s\e[0m:  %s\n" "no further posts" "${no_posts_check}"
   fi

: <<-'COMMENT'

   # works for Bash 3.0 or later
   if [[ "${website}" =~ '>No posts<' ]]; then 
      no_posts_check="${BASH_REMATCH[0]}"
      #printf "\e[0K\e[31m%s\e[0m:  %s\n" "no further posts" "${no_posts_check}"
   fi

COMMENT


   if [[ -z "${no_posts_check}" ]]; then

      # extract relevant post URLs
      #urls=( $(printf "%s\n" "${website}" | /usr/bin/sed -E -n -e "s|^.* href=\"(/posts/show/[[:digit:]]+)\".*$|${BaseURL}\1|p;g") )
      urls=( $(printf "%s\n" "${website}" | /usr/bin/egrep -o 'href="/posts/show/[[:digit:]]+"' | /usr/bin/sed -E -n -e "s|href=\"(/posts/show/[[:digit:]]+)\"|${BaseURL}\1|p;g") )

      for ((i=0; i < "${#urls[@]}"; i++)); do

         url="${urls[${i}]}"

         postnum="${url##*/}"
         file="${download_dir}/${postnum}"
         trap '/bin/rm -f "${file}"; exit 0' 0 1 2 13 15

         /usr/bin/curl -L -O -s --max-time $curl_max_time "${url}"

         if [[ $? -ne 0 ]]; then 
            printf "\e[0K\e[31m%s\e[0m:  %s\n" "curl_max_time ${curl_max_time}" "${url}"
            continue
         fi
 

         # get title of downloaded web page
         #title="$(/usr/bin/sed -E -n -e '/<[tT][iI][tT][lL][eE]>/{s/^.*<[tT][iI][tT][lL][eE]>(.*)<\/[tT][iI][tT][lL][eE]>.*$/\1/p;q;}' "${file}" | \
         #    /usr/bin/sed -E -e 's/\[[^][:space:]]*\]//g')"    # delete [xxx] tag elements of title

         title="$(/usr/bin/egrep -m 1 -io '<title>.*</title>' "${file}" | /usr/bin/sed -E -e 's/^<title>[[:space:]]*|[[:space:]]*<\/title>$//g' \
                -e 's/\[[^][:space:]]*\]//g')"    # delete [xxx] tag elements of title


         title="${title//CodeSnippets:/}"
         title="${title//\//:}"
         title="${title// /_}"
         title="${title//[[:cntrl:]]/}"
         title="${title%"${title##*[!_]}"}"   # remove trailing underscores

         #printf "%s\n" "${title}"

         if [[ $title == '_CodeDrive_Snippets_courtesy_of_Peter_Coopers_handy_little_app' ]] || [[ -z "$title" ]]; then
            printf "\e[0K\e[31m%s\e[0m:  %s\n" "couldn't access" "${url}"
            /bin/rm "${file}"
            continue
         fi

         outputfile="${download_dir}/${postnum}_${title}.txt"
         #outputfile="${download_dir}/${title}.txt"  # without post number prefix
         #outputfile="${outputfile//__/_}"  # uniq underscores

         let cnt++
         printf "\e[0K\e[1;32m%-6s\e[0m  %s\n" "${cnt}" "${outputfile##*/}"

         /usr/bin/textutil -output "${outputfile}" -convert txt -inputencoding "${InputEncoding}" -encoding "${OutputEncoding}" "${file}"

         /bin/rm "${file}"


         # escape backslashes
         # man bash 2>/dev/null | less -p 'Each command in a pipeline'
         #outputfile="$(printf "%q" "${outputfile}")"  # cf. help printf
         outputfile="${outputfile//\\/\\\\}"

# edit $outputfile in-place with man ed
# first delete lines at the beginning & end,
# then remove the string 'See related posts' and add some newlines with $NL,
# then convert the line 'to...by...on' to line 'Author:...', line 'Date:...', line 'URL:...' and line 'Tags:...'
# and finally the last two ed commands insert two further newlines with $NL

cat <<EOF | /bin/ed -s "${outputfile}"
H
,g/Snippets is a public source code repository/1,/Snippets is a public source code repository/d
,g/You need to create an account or log in to post comments to this site//You need to create an account or log in to post comments to this site/,\$d
,g|(See related posts)$|s|.See related posts.|${NL}${NL}|
,g|^to.* by.* on .*[[:digit:]]$|s|^to\(.*\) by\(.*\) on \(.*[[:digit:]]\)$|${NL}${NL}Author:\2${NL}Date: \3${NL}URL: ${url}${NL}Tags:\1${NL}|
,g|^Comments on this post$|s|\(Comments on this post\)|${NL}\1:|
,g| posts on .* at |s|\(.* posts on .* at .*\)|${NL}\1:|
w
EOF

# additional ed commands
# delete line numbers
# ,g|^[[:space:]]*[[:digit:]]\{1,\}[[:space:]]\{1,3\}|s|^[[:space:]]*[[:digit:]]\{1,\}[[:space:]]\{1,3\}\(.*\)$|\1|
# delete range of lines
# 4,11d


      done  # for

      let count++

   fi

done   # while


   cd "${OPWD}"


exit 0

Delete carriage returns & newlines with sed

# delete newlines

printf "a\nb\nc\nd\ne\nf" | sed -n -e 'l'
printf "a\nb\nc\nd\ne\nf" | sed -E -e :a -e '$!N; s/\n//g; ta'

printf "a\n\nb" | sed -n -e 'l'
printf "a\n\nb" | sed -E -e :a -e '$!N; s/\n//g; ta' | sed -n -e 'l'
printf "a\n\nb" | sed -E -e :a -e '$!N; s/\n$//g; ta' | sed -n -e 'l'
printf "a\n\n\n\n\n\nb" | sed -E -e :a -e '$!N; s/\n$//g; ta' | sed -n -e 'l'


# delete carriage returns

printf "he\r\rllo\n" | sed -n -e 'l'
printf "he\r\rllo\n" | sed -e s/$'\r'//g | sed -n -e 'l'
printf "he\r\rllo\n" | sed -e s/$'\r\r'/$'\r'/g | sed -n -e 'l'

CR=$'\r'
printf "hello\r\r\n" | sed "s/$CR$CR$/$CR/g" | sed -n -e 'l'


# alternatives

printf "a\nb\nc\nd\ne\nf" | tr -d '\n'

# cf. http://linux.dsplabs.com.au/rmnl-remove-new-line-characters-tr-awk-perl-sed-c-cpp-bash-python-xargs-ghc-ghci-haskell-sam-ssam-p65/
while read -d $'\n'; do echo -n "${REPLY} "; done < <((printf "a\nb\nc\nd\ne\nf"))
while read -d $'\n'; do printf "%s   " "${REPLY}"; done < <((printf "a\nb\nc\nd\ne\nf"))

xargs echo < <((printf "a\nb\nc\nd\ne\nf"))
xargs printf "%s " < <((printf "a\nb\nc\nd\ne\nf"))

printf "a\nb\nc\nd\ne\nf" | /usr/bin/paste -s -d ' ' -     # cf. man paste

# delete newlines in-place (also see below)
vim -e -s +':%j' +'w!' +'qa!' /path/to/file

# insert newlines again
printf "%s\n" "hello" | sed -e s/l/$'\\\n'/g | sed -n -e 'l'
printf "%s\n" "hello" | sed -E s/\(l\)/\\1$'\\\n'/g | sed -n -e 'l'


#-----------------------------------------------------------


# converting between \n and \n\r

# cf. also flip, http://ccrma.stanford.edu/~craig/utility/flip/ and 
# http://codesnippets.joyent.com/posts/show/1660


# convert \n into \r\n
printf "a\nb\nc\nd\ne\nf\n"
printf "a\nb\nc\nd\ne\nf\n" | sed -n -e 'l'

printf "a\nb\nc\nd\ne\nf\n" | sed s/$/$'\r'/
printf "a\nb\nc\nd\ne\nf\n" | sed s/$/$'\r'/ | sed -n -e 'l'

printf "a\nb\n\n\n\n\n\n\n\n\n\n\nc\nd\ne\nf\n" | sed -E -e :a -e '$!N; s/\n$//g; ta' | sed -E s/$/$'\r'/ | sed -n -e 'l'

while read -d $'\n'; do printf "%s\r\n" "${REPLY}"; done < <((printf "a\nb\nc\nd\ne\nf\n"))
while read -d $'\n'; do printf "%s\r\n" "${REPLY}"; done < <((printf "a\nb\nc\nd\ne\nf\n")) | sed -n -e 'l'


# convert \r\n into \n
printf "a\r\nb\r\nc\r\nd\r\ne\r\nf\r\n"
printf "a\r\nb\r\nc\r\nd\r\ne\r\nf\r\n" | sed -n -e 'l'

printf "a\r\nb\r\nc\r\nd\r\ne\r\nf\r\n" | sed s/$'\r'$//
printf "a\r\nb\r\nc\r\nd\r\ne\r\nf\r\n" | sed s/$'\r'$// | sed -n -e 'l'

printf "a\r\nb\r\r\r\r\r\r\r\r\r\r\nc\r\nd\r\ne\r\nf\r\n" | sed s/$'\r'*$// | sed -n -e 'l'
printf "a\r\nb\r\r\r\r\r\r\r\r\r\r\nc\r\nd\r\ne\r\nf\r\n" | sed -E s/$'\r'+$// | sed -n -e 'l'

# lacks a terminating \n though
while read -d $'\r'; do printf "%s" "${REPLY}"; done < <((printf "a\r\nb\r\nc\r\nd\r\ne\r\nf\r\n"))
while read -d $'\r'; do printf "%s" "${REPLY}"; done < <((printf "a\r\nb\r\nc\r\nd\r\ne\r\nf\r\n")) | sed -n -e 'l'


#---------------------------------------


# create test files

testfile="${HOME}/Desktop/testfile.txt"
output="${HOME}/Desktop/output.txt"

function createfiles() {

testfile="${HOME}/Desktop/testfile.txt"
output="${HOME}/Desktop/output.txt"

/usr/bin/touch "$output"

#/usr/bin/jot -b 'sample text' 10 | /bin/cat > "$testfile"
/usr/bin/jot -b 'sample text' 10 | /bin/cat -n > "$testfile"
printf "%s\r\n\r\n\r\r\n" "sample text" >> "$testfile"      # append a line with a '\r\n' line separator
printf "%s" "sample text" >> "$testfile"          # append a last line without a terminating '\n'

return 0
}

createfiles


# inspect test file

cat -vet "$testfile"
ed -s "$testfile" <<< $',l'
sed -n -e 'l'  "$testfile"
ruby -n -e 'p $_.to_s' < "$testfile"


function odcfile() {

/usr/bin/od -A n -c < "$@" | /usr/bin/sed -E -e 's/^[[:space:]]{11}//' \
       -e s/[[:space:]]{4}/$'\001'/g \
       -e 's/[[:space:]]+//g' | \
       /usr/bin/tr -d '\n' | /usr/bin/tr '\001' ' ' | \
       /usr/bin/sed -e s/\\\\n/$'\\\\\\n\\\n'/g 

return 0
}


odcfile "$testfile"


# remove newlines "\n"

# create a new file with newline characters replaced with a space
sed -e :a -e '$!N; s/\n/ /g; ta' "$testfile" > "$output"
odcfile "$output"

# same, but in-place
sed -i "" -e :a -e '$!N; s/\n/ /g; ta' "$testfile"
odcfile "$testfile"

createfiles

# delete newlines in-place
sed -i "" -e :a -e '$!N; s/\n//g; ta' "$testfile"
odcfile "$testfile"

createfiles

# alternative for creating a new file without newlines
tr -d '\n' < "$testfile" > "$output"
odcfile "$output"



# delete carriage returns "\r"

# create a new file with carriage returns deleted
sed -e s/$'\r'//g "$testfile" > "$output"
sed -e s/$'\r'$//g "$testfile" > "$output"  # only at line end
odcfile "$output"

# alternative
tr -d '\r' < "$testfile" > "$output"
odcfile "$output"


# delete carriage returns in-place

sed -i "" -e s/$'\r'//g "$testfile" > "$output"
odcfile "$testfile"

createfiles

# cf. http://bash-hackers.org/wiki/doku.php?id=howto:edit-ed (Pitfalls)
ed -s "$testfile" <<< $'H\n,g/\r/s/\r//\n,w'      # delete one carriage return in a line
ed -s "$testfile" <<< $'H\n,g/\r/s/\r//g\n,w'     # delete all carriage returns in a line
ed -s "$testfile" <<< $'H\n,g/\r$/s/\r$//g\n,w'   # delete a carriage return at line end

odcfile "$testfile"



printf "\n" | od -A n -c
printf "\012" | od -A n -c
printf "\x0a" | od -A n -c

printf '[ctrl-v][ctrl-j]' | od -A n -c      #  \n or ^J


printf "\r" | od -A n -c
printf "\015" | od -A n -c
printf "\x0d" | od -A n -c

printf '[ctrl-v][ctrl-j]' | od -A n -c      #  \r or ^M


# vim
createfiles

vim "$testfile"
#...
:set number
:set list
:%s/^M//g
:set fileformat=unix
#:set fileformat=dos
:x

odcfile "$testfile"


# edit files in-place with vim

createfiles

# delete newlines in-place
vim -e -s +':%j' +'w!' +'qa!' "$testfile"
odcfile "$output"

createfiles

# replace every \r with \n
# cf. http://vim.wikia.com/wiki/Change_end-of-line_format_for_dos-mac-unix
vim -e -s +':%s/\r/\r/g' +':set fileformat=unix' +'w!' +'qa!' "$testfile"
odcfile "$output"

createfiles

# delete every \r
vim -e -s +':%s/\r//g' +':set fileformat=unix' +'w!' +'qa!' "$testfile"
odcfile "$output"

createfiles

# delete \r only when it occurs at the end of a line
vim -e -s +':%s/\r$//g' +':set fileformat=unix' +'w!' +'qa!' "$testfile"
odcfile "$output"

createfiles

# replace carriage return line endings with \n
# cf. Getting rid of ^M - mixing dos and unix, http://www.vim.org/tips/tip.php?tip_id=26
printf "\r" >> "$testfile"
vim -e -s +':g/\r$/s///g' +':set fileformat=unix' +'w!' +'qa!' "$testfile"
odcfile "$testfile"

createfiles

# delete last \n of file
vim -e -s +':set noeol bin' +':set fileformat=unix' +'w!' +'qa!' "$testfile"
odcfile "$output"

createfiles

# change mixed mode files to DOS mode
#vim -e -s +':%s/\r\r/\r/g' +'w!' +'qa!' "$testfile"
sed -i '' -e s/$'\r\r'/$'\r'/g  "$testfile"
vim -e -s +':e ++ff=dos' +'w!' +'qa!' "$testfile"
vim -e -s +':e ++ff=dos' +':set ff=dos' +'w!' +'qa!' "$testfile"
odcfile "$output"

vim "$testfile"
:set ff?
:x

snippet

Download code snippets (http://codesnippets.joyent.com) from the command line and convert them to text files using man textutil (on Mac OS X 10.4).

Usage:
snippet 345
snippet 1268
snippet 1281
snippet 182
snippet 1282
snippet 1115
snippet 5
snippet 23444


# $ cat $HOME/.bashrc

function snippet() {

   declare NL OPWD download_dir outputfile postnum title url

   if [[ "${1//[[:digit:]]/}" != "" ]]; then echo "Argument error. No positive integer: ${1}"; return 1; fi

   postnum="${1}"
   url="http://codesnippets.joyent.com/posts/show/${postnum}"
   download_dir="${HOME}/Desktop/Snippets"
   download_dir="${download_dir%/}"
   #printf "\n\e[0K\e[1;30m%s\e[0m:  %s\n\n" "download directory" "${download_dir}"
   /bin/mkdir -p "${download_dir}"
   OPWD="$PWD"
   cd "${download_dir}"
   /usr/bin/curl -L -O -s --max-time 25 "${url}" || exit 1    # download snippet
   file="${download_dir}/${url##*/}"

   title="$(/usr/bin/sed -E -n -e '/<[tT][iI][tT][lL][eE]>/{s/^.*<[tT][iI][tT][lL][eE]>(.*)<\/[tT][iI][tT][lL][eE]>.*$/\1/p;q;}' "${file}" | \
             sed -E -e 's/\[[^][:space:]]*\]//g')"    # delete [xxx] tag elements of title

   title="${title//CodeSnippets:/}"
   title="${title//\//:}"
   title="${title// /_}"
   title="${title//[[:cntrl:]]/}"
   title="${title%"${title##*[!_]}"}"   # remove trailing "_" characters

   if [[ $title == '_CodeDrive_Snippets_courtesy_of_Peter_Coopers_handy_little_app' ]] || [[ -z "$title" ]]; then
      printf "\e[0K\e[31m%s\e[0m:  %s\n" "couldn't access" "${url}"
      /bin/rm "${file}"
      return 1
   fi

   outputfile="${HOME}/Desktop/Snippets/${postnum}_${title}.txt"
   #outputfile="${outputfile//__/_}"  # uniq underscores

   printf "\n\e[0K\e[1;30m%s\e[0m:  %s\n\n" "saved as" "${outputfile}"

   /usr/bin/textutil -output "${outputfile}" -convert txt "${file}"
   /bin/rm "${file}"

   # escape backslashes
   # man bash 2>/dev/null | less -p 'Each command in a pipeline'
   #outputfile="$(printf "%q" "${outputfile}")"  # cf. help printf
   outputfile="${outputfile//\\/\\\\}"

   NL=$'\\\n'

cat <<EOF | /bin/ed -s "${outputfile}"
H
,g/Snippets is a public source code repository/1,/Snippets is a public source code repository/d
,g/You need to create an account or log in to post comments to this site//You need to create an account or log in to post comments to this site/,\$d
,g|(See related posts)$|s|.See related posts.|${NL}${NL}|
,g|^to.* by.* on .*[[:digit:]]$|s|^to\(.*\) by\(.*\) on \(.*[[:digit:]]\)$|${NL}${NL}Author:\2${NL}Date: \3${NL}URL: ${url}${NL}Tags:\1${NL}|
,g|^Comments on this post$|s|\(Comments on this post\)|${NL}\1:|
,g| posts on .* at |s|\(.* posts on .* at .*\)|${NL}\1:|
w
EOF

   cd "$OPWD"
   return 0

}