1 | #! /bin/bash
|
---|
2 | #
|
---|
3 | # original from:
|
---|
4 | # @(#) ncp.ksh,nmv.ksh 1.1 94/07/23
|
---|
5 | # 92/01/18 john h. dubois iii (john@armory.com)
|
---|
6 | # 92/01/31 added check for no args left after shifts
|
---|
7 | # 92/02/17 added help
|
---|
8 | # 92/02/25 remove path component from filename before tacking it onto dest.
|
---|
9 | # 92/03/15 exec mv or cp
|
---|
10 | # 93/07/13 Added -i
|
---|
11 | # 93/09/29 Made abort if file exists optional.
|
---|
12 | # 93/11/19 Exit before invoking mv if no files to move
|
---|
13 | # 94/01/03 Added o option
|
---|
14 | # 94/04/13 Added x option.
|
---|
15 | # Fixed appending of source filename, broken by earlier change.
|
---|
16 | # 94/07/23 Append only the filename part of the source path.
|
---|
17 | #
|
---|
18 | # conversion to bash v2 syntax done by Chet Ramey
|
---|
19 |
|
---|
20 | false()
|
---|
21 | {
|
---|
22 | return 1
|
---|
23 | }
|
---|
24 |
|
---|
25 | true()
|
---|
26 | {
|
---|
27 | return 0
|
---|
28 | }
|
---|
29 |
|
---|
30 | phelp()
|
---|
31 | {
|
---|
32 | echo "$name: do a $cmd with extra checking and options.
|
---|
33 | $Usage
|
---|
34 | $name is used as a front end for $cmd to get the [icfo] options, and so
|
---|
35 | that a trailing / will force the last component of the path to be
|
---|
36 | interpreted as a directory, so that $name foo bar/ will fail if bar is
|
---|
37 | not an existing directory, instead of changing the name of foo to bar.
|
---|
38 | Effectively, $name foo bar/ is short for $name foo bar/foo
|
---|
39 | Options:
|
---|
40 | -h prints this help.
|
---|
41 | -c checks first for the existence of each file, and fails if it exists.
|
---|
42 | -i is like -c except that if the file exists and stdin and stdout are a
|
---|
43 | tty, a query is printed and a reply is read; a file is overwritten only
|
---|
44 | if the reply begins with 'y'.
|
---|
45 | -f unsets -c and -i (in case $cmd is aliased to $name).
|
---|
46 | -o (overwrite only) checks that the named file(s) exist and fails for any
|
---|
47 | that do not. It is the complement of the -c option.
|
---|
48 | Whichever of [cifo] comes later on the command line determines the behaviour.
|
---|
49 | Any of these options must come before any standard $cmd options."
|
---|
50 | }
|
---|
51 |
|
---|
52 | # interactive: Attempt to overwrite file should result in interactive
|
---|
53 | # query rather than automatic failure.
|
---|
54 | # noover: Do not overwrite files (if interactive is true, query, else fail)
|
---|
55 | # overwrite: Only overwriting is allowed, not creation of new files.
|
---|
56 | # debug: Print debugging info.
|
---|
57 | typeset interactive=false noover=false overwrite=false debug=false
|
---|
58 | name=${0##*/}
|
---|
59 |
|
---|
60 | case "$name" in
|
---|
61 | ncp|nmv) cmd=/bin/${name#?} ;;
|
---|
62 | *) echo "$name: Must be invoked as ncp or nmv." 1>&2 ; exit 2;;
|
---|
63 | esac
|
---|
64 |
|
---|
65 | Usage="Usage: $name [-cfhio] $cmd-cmd-line"
|
---|
66 |
|
---|
67 | while getopts :cfhiox opt; do
|
---|
68 | case $opt in
|
---|
69 | h) phelp; exit 0;;
|
---|
70 | x) debug=true ;;
|
---|
71 | c) noover=true ;;
|
---|
72 | i) noover=true ; interactive=true ;;
|
---|
73 | f) noover=false ; interactive=false ;;
|
---|
74 | o) overwrite=true ; noover=false ; interactive=false;;
|
---|
75 | +?) echo "$name: options should not be preceded by a '+'." 1>&2; exit 2;;
|
---|
76 | ?) echo "$name: $OPTARG: bad option. Use -h for help." 1>&2 ; exit 2;;
|
---|
77 | esac
|
---|
78 | done
|
---|
79 |
|
---|
80 | # remove args that were options
|
---|
81 | shift $((OPTIND - 1))
|
---|
82 |
|
---|
83 | if [ $# -lt 2 ]; then
|
---|
84 | echo -e "$Usage\nUse -h for help."
|
---|
85 | exit
|
---|
86 | fi
|
---|
87 |
|
---|
88 | Check()
|
---|
89 | {
|
---|
90 | if [ ! -f "$1" ] && $overwrite; then
|
---|
91 | echo "$name: $1: File does not exist." 1>&2
|
---|
92 | return 1
|
---|
93 | elif [ -f "$1" ] && $noover; then
|
---|
94 | if [ $interactive = false ] || [ ! -t 0 ] || [ ! -t 1 ]; then
|
---|
95 | echo "$name: $1: File exists." 1>&2
|
---|
96 | return 1
|
---|
97 | else
|
---|
98 | while :; do
|
---|
99 | echo -n \
|
---|
100 | "$name: $1: File exists. Overwrite? (y)es/(n)o/(a)bort/(Y)es for all: " 1>&2
|
---|
101 | read reply
|
---|
102 | case "$reply" in
|
---|
103 | y*)
|
---|
104 | echo "$name: Overwriting $1."
|
---|
105 | return 0
|
---|
106 | ;;
|
---|
107 | Y*)
|
---|
108 | echo "$name: Overwriting $1."
|
---|
109 | interactive=false
|
---|
110 | noover=false
|
---|
111 | return 0
|
---|
112 | ;;
|
---|
113 | [nN]*)
|
---|
114 | echo "$name: Skipping $2."
|
---|
115 | return 1
|
---|
116 | ;;
|
---|
117 | [aA]*)
|
---|
118 | echo "$name: Aborting."
|
---|
119 | exit 1
|
---|
120 | ;;
|
---|
121 | *)
|
---|
122 | echo "$name: Invalid response." 1>&2
|
---|
123 | ;;
|
---|
124 | esac
|
---|
125 | done
|
---|
126 | fi
|
---|
127 | else
|
---|
128 | return 0
|
---|
129 | fi
|
---|
130 | }
|
---|
131 |
|
---|
132 | # i is the index of the filename being examined
|
---|
133 | # lastarg is the index of the last filename before the dest directory name
|
---|
134 | typeset -i i=0 lastarg=$(($#-1))
|
---|
135 |
|
---|
136 | # Sets argv[0..$#-1]
|
---|
137 | argv=("$@")
|
---|
138 | $debug && echo argv = "${argv[@]}" 1>&2
|
---|
139 | dest=${argv[lastarg]}
|
---|
140 |
|
---|
141 | if $debug; then
|
---|
142 | echo \
|
---|
143 | "interactive=$interactive noover=$noover overwrite=$overwrite debug=$debug
|
---|
144 | lastarg=$lastarg dest=$dest name=$name cmd=$cmd
|
---|
145 | files=$*" 1>&2
|
---|
146 | fi
|
---|
147 |
|
---|
148 | if $noover || $overwrite; then
|
---|
149 | $debug && echo "checking for existance of directories..." 1>&2
|
---|
150 | # If the destination is not intended to be a directory...
|
---|
151 | if [ $# -eq 2 ] && [ ! -d "$dest" ]; then
|
---|
152 | Check "$dest" "$1" || exit 0 # No files to copy
|
---|
153 | else
|
---|
154 | while [ $i -lt $lastarg ]; do
|
---|
155 | Check "$dest/${argv[i]##*/}" "${argv[i]}" || unset argv[i]
|
---|
156 | let i+=1
|
---|
157 | done
|
---|
158 | fi
|
---|
159 | fi
|
---|
160 |
|
---|
161 | [ ${#argv[@]} -lt 2 ] && exit 0
|
---|
162 |
|
---|
163 | # If only 2 args are given, mv/cp will not insist that the destination
|
---|
164 | # be a directory, which we want if the destination ends in "/" or if
|
---|
165 | # the original number of args was >2.
|
---|
166 | # $# is still the original number of args.
|
---|
167 | # Tack the file name onto the destination to force this behaviour.
|
---|
168 |
|
---|
169 | lastisslash()
|
---|
170 | {
|
---|
171 | case "$1" in
|
---|
172 | */) return 0;;
|
---|
173 | *) return 1;;
|
---|
174 | esac
|
---|
175 | }
|
---|
176 |
|
---|
177 | if [ ${#argv[@]} = 2 ] && { lastisslash "$2" || [ $# -gt 2 ]; }; then
|
---|
178 | $debug && echo "Appending filename." 1>&2
|
---|
179 | # Don't know which element of argv[] holds the source filename,
|
---|
180 | # since may have started with more than 1 source file & had some unset.
|
---|
181 | # So, compact args to make it easy to find the set one.
|
---|
182 | argv=("${argv[@]}")
|
---|
183 | argv[1]="${argv[1]}/${argv[0]##*/}"
|
---|
184 | fi
|
---|
185 |
|
---|
186 | $debug && echo "Executing command: $cmd ${argv[@]}" 1>&2
|
---|
187 | exec $cmd "${argv[@]}"
|
---|