From da6d7b188f4797731147700af5e4ea078bbb517a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20L=C3=B3pez?= Date: Wed, 4 Nov 2015 22:56:36 -0600 Subject: [PATCH] update virn make virn sh posix portable add directory support add options, --editor, --help add usage --- virn | 161 +++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 124 insertions(+), 37 deletions(-) diff --git a/virn b/virn index 6745cfb..d467f20 100755 --- a/virn +++ b/virn @@ -1,48 +1,135 @@ -#!/usr/bin/env bash +#!/bin/sh # virn, Copyright (C) 2007-2010 by Jonas Kramer. All rights reserved. # Published under the terms of the GNU General Public License (GPL). -# This is a more portable BASH remake of my old script "vimove" which depended -# on ZSH. +_usage() +{ + printf "%s\\n" "Usage: $(expr "${0}" : '.*/\([^/]*\)') [options] file ..." >&2 + printf "%s\\n" "Rename lots of files using your favorite text editor." >&2 + printf "\\n" >&2 + printf "%b\\n" " -e, --editor use this editor instead of the default \$EDITOR" >&2 + printf "%b\\n" " -h, --help show this help message and exit" >&2 + exit 1 +} -die () { - echo "$@" >&2 - exit -1 +_die() +{ + [ -z "${1}" ] && return 1 + printf "%b\\n" "$(expr "${0}" : '.*/\([^/]*\)'): ${*}" >&2 + exit 1 } -# Verify that there's an $EDITOR defined. -[ -z "$EDITOR" ] && die '$EDITOR not defined.' +_mkdir_p() +{ #portable mkdir -p function + for _mkdir_p__dir; do + _mkdir_p__IFS="$IFS" + IFS="/" + set -- $_mkdir_p__dir + IFS="$_mkdir_p__IFS" + ( + case "$_mkdir_p__dir" in + /*) cd /; shift ;; + esac + for _mkdir_p__subdir; do + [ -z "${_mkdir_p__subdir}" ] && continue + if [ -d "${_mkdir_p__subdir}" ] || mkdir "${_mkdir_p__subdir}"; then + if cd "${_mkdir_p__subdir}"; then + : + else + printf "%s\\n" "_mkdir_p: Can't enter ${_mkdir_p__subdir} while creating ${_mkdir_p__dir}" + exit 1 + fi + else + exit 1 + fi + done + ) + done + unset _mkdir_p__dir +} -# Exit before doing anything if there are no arguments anyway. -ARGV=("$@") -[ $# -eq 0 ] && exit +_dirname() +{ #return string containing dirname on success, 1 on failure + [ -z "${1}" ] && return 1 -# Create targets file. -TARGETS="/tmp/virn-$RANDOM" -for FILE in "$@"; do echo "$FILE" >> $TARGETS; done - -# Start the $EDITOR so we can edit our file names. -if $EDITOR $TARGETS; then - FILENO=0 - COUNT="`wc -l $TARGETS | sed -nre 's/^[ \t]*([0-9]+).*$/\1/p'`" - - # Exit with error message if number of arguments and line count of - # targets file differ. - if [ "$COUNT" -ne "$#" ]; then - rm $TARGETS - die 'Numbers of files mismatch.' - fi - - # Read targets file line by line and rename the source - # files from ARGV appropriately. - while read TARGET; do - SOURCE="${ARGV[$FILENO]}" - if [ "$SOURCE" != "$TARGET" ]; then - mv -f -- "$SOURCE" "$TARGET" - fi - FILENO=$[$FILENO+1] - done < $TARGETS + #http://www.linuxselfhelp.com/gnu/autoconf/html_chapter/autoconf_10.html + case "${1}" in + /*|*/*) _dirname__dir=$(expr "x${1}" : 'x\(.*\)/[^/]*' \| '.' : '.') + printf "%s\\n" "${_dirname__dir}" ;; + *) printf "%s\\n" ".";; + esac +} + +if [ ! -t 0 ]; then + #there is input comming from pipe or file, add to the end of $@ + set -- "${@}" $(cat) fi -rm $TARGETS +[ "${#}" -eq "0" ] && _usage + +for arg; do #parse options + case "${arg}" in + -h|--help) _usage ;; + -e|--editor) + if [ "${#}" -gt "1" ]; then + editor="$(printf "%s " "${@}" | awk '{print $2}')" + shift && shift + else + _die "Option \`${arg}' requires a parameter" + fi ;; + -*) printf "%s\\n" "$(expr "${0}" : '.*/\([^/]*\)'): unrecognized option \`${arg}'" >&2; _usage ;; + esac +done + +[ -z "${editor}" ] && editor="${EDITOR}" +[ -z "${EDITOR}" ] && _die "\${EDITOR} not defined." + +# Create targets file. +targets="/tmp/virn-${$}" +i=0; for FILE; do + [ -e "${FILE}" ] || { + i="$((i+1))"; + printf "%s\\n" "Warning: '${FILE}' doesn't exist, skipping ..." >&2 ; + continue; } + printf "%s\\n" "${FILE}" >> "${targets}" +done + +[ ! -f "${targets}" ] && exit + +# Start $EDITOR +if ${editor} ${targets}; then + [ ! -t 0 ] && reset + count="$(awk 'END {print NR}' "${targets}" 2>/dev/null)" + param_len="${#}"; param_len="$((param_len - i))" + + # Exit with error message if number of arguments and line count of + # targets file differ. + if [ "${count}" -ne "${param_len}" ]; then + rm -- "${targets}" + _die 'Numbers of files mismatch.' + fi + + # Read targets file line by line and rename the source + # files from ARGV appropriately. + while read target; do + while [ ! -e "${source}" ]; do + source="${1}" + shift + done + if [ X"${source}" != X"${target}" ]; then + case "${target}" in + /*|*/*) + target="$(printf "%s" "${target}" | \ + sed "s:\$HOME:$HOME:g;s:~/:$HOME/:;")" + _mkdir_p "$(_dirname "${target}")" ;; + esac + mv -v -f -- "${source}" "${target}" + case "${source}" in + /*|*/*) rmdir -p "$(_dirname "${source}")" 2>/dev/null ;; + esac + fi + source="" + done < "${targets}" +fi +rm "${targets}"