-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcp_pp
More file actions
executable file
·247 lines (205 loc) · 6.91 KB
/
Copy pathcp_pp
File metadata and controls
executable file
·247 lines (205 loc) · 6.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
#!/bin/bash
## Bash settings
set -uo pipefail
## Script globals
script_name=$(basename "${BASH_SOURCE[0]}")
script_dir=$({ cd "$(dirname "${BASH_SOURCE[0]}")" || { echo "Failed to access script file directory" >&2; exit; } } && pwd)
script_dir_abs=$({ cd "$(dirname "${BASH_SOURCE[0]}")" || { echo "Failed to access script file directory" >&2; exit; } } && pwd -P)
script_file="${script_dir}/${script_name}"
if [ -L "${BASH_SOURCE[0]}" ]; then
script_file_abs=$(readlink "${BASH_SOURCE[0]}")
else
script_file_abs="${script_dir_abs}/${script_name}"
fi
export CURRENT_PARENT_BASH_SCRIPT_FILE="$script_file"
script_args=("$@")
## Script imports
lib_dir="${script_dir}/../lib"
bash_functions_script="${lib_dir}/bash_script_func.sh"
## Source imports
source "$bash_functions_script"
## Arguments
path_arg_arr=()
prefix=''
fwd_args_arr=()
dryrun=false
## Custom globals
target_dir_arg_provided=false
dst_dir=''
dst_file=''
dst_fname=''
## Script usage
read -r -d '' script_usage << EOM
${script_name} ("cp --parents PLUS") Usage:
${script_name} [OPTION]... [-T] SOURCE DEST
${script_name} [OPTION]... SOURCE... DIRECTORY
${script_name} [OPTION]... -t DIRECTORY SOURCE...
(see 'man cp' for further details)
Copy file(s) with 'cp', first creating destination directory
with 'mkdir -p' if the destination directory does not exist.
Options:
[all 'cp' options]
--prefix=<string>
Append this string to the name of the destination
file(s).
-db,--debug
-dr,--dryrun
Print 'cp' commands used to copy, without executing.
EOM
if (( $# < 1 )); then
echo_e -e "$script_usage"
exit_script_with_status 1
fi
## Parse arguments
set +u
while (( $# > 0 )); do
arg="$1"
if [ "$(string_startswith "$arg" '-')" = false ]; then
path_arg_arr+=( "$arg" )
else
arg_opt="$(string_lstrip "$arg" '-')"
arg_opt_nargs=''
if [ "$(string_contains "$arg_opt" '=')" = true ]; then
arg_val=$(printf '%s' "${arg_opt#*=}" | sed -r -e "s|^['\"]+||" -e "s|['\"]+$||")
arg_opt="${arg_opt%%=*}"
arg_opt_raw="${arg%%=*}"
arg_opt_nargs_do_shift=false
else
arg_val="$2"
arg_opt_raw="$arg"
arg_opt_nargs_do_shift=true
fi
arg_val_can_start_with_dash=false
if [ "$arg_opt" = 'h' ] || [ "$arg_opt" = 'help' ]; then
arg_opt_nargs=0
echo "$script_usage"
exit 0
elif [ "$arg_opt" = 'prefix' ]; then
arg_opt_nargs=1
prefix="$arg_val"
elif [ "$arg_opt" = 'db' ] || [ "$arg_opt" = 'debug' ]; then
arg_opt_nargs=0
dryrun=true
elif [ "$arg_opt" = 'dr' ] || [ "$arg_opt" = 'dryrun' ]; then
arg_opt_nargs=0
dryrun=true
else
if [ "$(itemOneOf "$arg_opt" 't' 'target-directory' )" = true ]; then
arg_opt_nargs=1
target_dir_arg_provided=true
dst_dir="$arg_val"
elif [ "$(itemOneOf "$arg_opt" 'S' 'suffix' 't' 'target-directory' )" = true ]; then
arg_opt_nargs=1
if [ "$(string_contains "$arg_val" '*')" = true ] || [ "$(string_contains "$arg_val" ' ')" = true ]; then
arg_val="\"${arg_val}\""
fi
fwd_args_arr+=( "$arg_opt_raw" "$arg_val" )
else
arg_opt_nargs=0
if [ "$(string_contains "$arg" '*')" = true ] || [ "$(string_contains "$arg" ' ')" = true ]; then
arg="\"${arg}\""
fi
fwd_args_arr+=( "$arg" )
fi
fi
if [ -z "$arg_opt_nargs" ]; then
echo_e "Developer error! "'$arg_opt_nargs'" was not set for argument: ${arg}"
exit_script_with_status 1
fi
if [ "$arg_opt_nargs_do_shift" = true ] && (( arg_opt_nargs >= 1 )); then
for arg_num in $(seq 1 $arg_opt_nargs); do
shift
arg_val="$1"
if [ -z "$arg_val" ]; then
echo_e "Missing expected value (#${arg_num}) for argument: ${arg}"
exit_script_with_status 1
elif [ "$arg_val_can_start_with_dash" = false ] && [ "$(string_startswith "$arg_val" '-')" = true ]; then
echo_e "Unexpected argument value: ${arg} ${arg_val}"
exit_script_with_status 1
fi
done
fi
fi
shift
done
set -u
## Validate arguments
num_path_args="${#path_arg_arr[@]}"
if (( num_path_args == 0 )); then
echo_e "At least one SOURCE argument must be provided"
exit_script_with_status 1
elif (( num_path_args == 1 )) || [ "$target_dir_arg_provided" = true ]; then
last_target_idx=$(( num_path_args - 1 ))
dst_is_dir=true
else
last_target_idx=$(( num_path_args - 2 ))
dst_idx=$(( num_path_args - 1 ))
destination="${path_arg_arr[$dst_idx]}"
if (( num_path_args > 2 )) || [ "$(string_endswith "$destination" '/')" = true ]; then
dst_dir="$destination"
dst_is_dir=true
else
dst_file="$destination"
dst_fname=$(basename "$dst_file")
dst_dir=$(dirname "$dst_file")
dst_is_dir=false
fi
fi
if [ "$dst_is_dir" = true ]; then
if [ -z "$dst_dir" ]; then
echo_e "Destination directory must be specified"
exit_script_with_status 1
elif [ -e "$dst_dir" ] && [ ! -d "$dst_dir" ]; then
echo_e "Non-directory path already exists at DEST location: ${dst_dir}"
exit_script_with_status 1
fi
fi
srcfile_path_arr=()
for idx in "${!path_arg_arr[@]}"; do
if (( idx > last_target_idx )); then
break
fi
srcfile="${path_arg_arr[$idx]}"
if [ ! -f "$srcfile" ]; then
echo_e "SOURCE path is not an existing file: ${srcfile}"
exit_script_with_status 1
fi
srcfile_path_arr+=( "$srcfile" )
done
## Create destination directory if needed
if [ -n "$dst_dir" ] && [ ! -d "$dst_dir" ]; then
cmd="mkdir -p \"${dst_dir}\""
if [ "$dryrun" = true ]; then
echo "$cmd"
else
eval "$cmd"
cmd_status=$?
if (( cmd_status != 0 )); then
echo_e "Received non-zero exit status (${cmd_status}) from mkdir command"
echo_e "mkdir -p ${dst_dir}"
echo_e "Exiting before copying file(s)"
exit_script_with_status 1
fi
fi
fi
## Perform copying
cp_args="${fwd_args_arr[*]+${fwd_args_arr[*]}}"
for srcfile in "${srcfile_path_arr[@]}"; do
srcfname=$(basename "$srcfile")
if [ -n "$prefix" ]; then
if [ -n "$dst_fname" ]; then
dstfname="${prefix}${dst_fname}"
else
dstfname="${prefix}${srcfname}"
fi
else
dstfname="$srcfname"
fi
dstfile="${dst_dir}/${dstfname}"
cmd="cp ${cp_args} \"${srcfile}\" \"${dstfile}\""
if [ "$dryrun" = true ]; then
echo "$cmd"
else
eval "$cmd"
fi
done