]> git.ipfire.org Git - thirdparty/bash.git/blame - examples/scripts.v2/ncp
Bash-4.2 patch 45
[thirdparty/bash.git] / examples / scripts.v2 / ncp
CommitLineData
ccc6cda3
JA
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
20false()
21{
22 return 1
23}
24
25true()
26{
27 return 0
28}
29
30phelp()
31{
32echo "$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
35that a trailing / will force the last component of the path to be
36interpreted as a directory, so that $name foo bar/ will fail if bar is
37not an existing directory, instead of changing the name of foo to bar.
38Effectively, $name foo bar/ is short for $name foo bar/foo
39Options:
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.
48Whichever of [cifo] comes later on the command line determines the behaviour.
49Any 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.
57typeset interactive=false noover=false overwrite=false debug=false
58name=${0##*/}
59
60case "$name" in
61ncp|nmv) cmd=/bin/${name#?} ;;
62*) echo "$name: Must be invoked as ncp or nmv." 1>&2 ; exit 2;;
63esac
64
65Usage="Usage: $name [-cfhio] $cmd-cmd-line"
66
67while 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
78done
79
80# remove args that were options
81shift $((OPTIND - 1))
82
83if [ $# -lt 2 ]; then
84 echo -e "$Usage\nUse -h for help."
85 exit
86fi
87
88Check()
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
134typeset -i i=0 lastarg=$(($#-1))
135
136# Sets argv[0..$#-1]
137argv=("$@")
138$debug && echo argv = "${argv[@]}" 1>&2
139dest=${argv[lastarg]}
140
141if $debug; then
142 echo \
143"interactive=$interactive noover=$noover overwrite=$overwrite debug=$debug
144lastarg=$lastarg dest=$dest name=$name cmd=$cmd
145files=$*" 1>&2
146fi
147
148if $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
159fi
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
169lastisslash()
170{
171 case "$1" in
172 */) return 0;;
173 *) return 1;;
174 esac
175}
176
177if [ ${#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]##*/}"
184fi
185
186$debug && echo "Executing command: $cmd ${argv[@]}" 1>&2
187exec $cmd "${argv[@]}"