ajout de gestion de bdd pour...
|
1 |
#!/bin/bash |
2 | ||
ré-écriture complète
|
3 |
set -e |
4 | ||
5 |
declare -A data=( |
|
6 |
[/sim/description]=text |
|
7 |
[/sim/long-description]=text |
|
8 |
[/sim/author]=text |
|
9 |
[/sim/flight-model]=text |
|
10 |
[/sim/type]=text |
|
11 |
[/sim/model/path]=text |
|
12 |
) |
|
ajout de gestion de bdd pour...
|
13 |
fgaddon_svn=https://svn.code.sf.net/p/flightgear/fgaddon/trunk/Aircraft |
many improvement
|
14 |
fgaddon_path=$HOME/.fgfs/flightgear-fgaddon/Aircraft |
ré-écriture complète
|
15 |
database=${DB:-$0.db} |
16 |
#locale=fr |
|
17 | ||
18 |
test -r "$0.conf" && source $0.conf && echo config red |
|
19 | ||
ajout de gestion de bdd pour...
|
20 | |
21 |
aircrafts=$(mktemp --dry-run /dev/shm/Aircraft-XXXXXXXXX) |
|
22 |
aircraft=$(mktemp --dry-run /dev/shm/aircraft-XXXXXXX) |
|
23 |
setxml=$(mktemp --dry-run /dev/shm/setxml-XXXXXXXX) |
|
24 |
in_ram_database=$(mktemp --dry-run /dev/shm/XXXXXXX) |
|
25 | ||
26 | ||
ré-écriture complète
|
27 |
function xmlgetnext () { |
28 |
local IFS='>' |
|
29 |
read -d '<' TAG VALUE |
|
30 |
# by design, the first TAG/VALUE pair is empty |
|
31 |
# to avoid infinite loops at end of file parsing we return an error |
|
32 |
# the next time we find an empty TAG |
|
33 |
if test -z "$TAG"; then |
|
34 |
test ${xmlgetnext_firstentry:-1} -eq 1 && xmlgetnext_firstentry=0 || return 1; |
|
35 |
fi |
|
36 |
# process $TAG only if necessary |
|
37 |
local _TAG=$(printf '%q' $TAG) |
|
38 |
if test ${_TAG:0:1} = '$'; then |
|
39 |
TAG=$(tr '\n' ' ' <<< $TAG | sed 's/ */ /g; s/ *$//') |
|
40 |
fi |
|
ajout de gestion de bdd pour...
|
41 |
} |
42 | ||
keep journal of sqlite reque...
|
43 |
rm -f /dev/shm/sqlite_request |
ajout de gestion de bdd pour...
|
44 |
function sqlite_request () { |
keep journal of sqlite reque...
|
45 |
local delimiter=';' |
46 |
test ${1:0:1} == '.' && delimiter='' |
|
47 |
echo "${1}${delimiter}" >> /dev/shm/sqlite_request |
|
ré-écriture complète
|
48 |
if ! sqlite3 "$in_ram_database" <<< "$1"; then |
49 |
register_state |
|
50 |
fi |
|
51 |
} |
|
52 | ||
53 |
function xmlremovecomments () { |
|
54 |
sed -ri 's/<(!--|script>)/\n&/;s/(<\/script|--)>/&\n/' $setxml |
|
55 |
sed -ri '/<(script>|!--).*(<\/script|--)>/d;/<(script>|!--)/,/(<\/script|--)>/d' $setxml |
|
small stuff
|
56 |
sed -i 's/\xef\xbb\xbf//' $setxml # removes BOM |
ré-écriture complète
|
57 |
} |
58 | ||
59 |
function trap_break () { |
|
60 |
trap '' INT |
|
61 |
echo "stop requested" |
|
62 |
register_state |
|
ajout de gestion de bdd pour...
|
63 |
} |
64 | ||
65 |
function trap_exit () { |
|
ré-écriture complète
|
66 |
trapped_rc=$? |
67 |
trap '' INT |
|
68 |
rm -f $aircrafts $aircraft $setxml |
|
69 |
if test ! -e $in_ram_database; then |
|
70 |
exit |
|
71 |
fi |
|
72 |
test $trapped_rc -ne 0 && register_state |
|
many improvements
|
73 |
echo "updating installation status" |
ré-écriture complète
|
74 |
for ac in $(sqlite_request 'select printf("%i:%s/%s", aircrafts.id, aircrafts.name, setxml.file) |
75 |
from aircrafts inner join setxml |
|
76 |
where aircrafts.id = setxml.variantof and setxml.installed != 0;'); do |
|
many improvements
|
77 |
ac_path=${ac#*:} |
many improvement
|
78 |
if test ! -e $fgaddon_path/$ac_path-set.xml; then |
79 |
sqlite_request "update setxml set installed = 0 where file = '${ac_path#*/}' and variantof = ${ac%:*}" |
|
80 |
fi |
|
81 |
done |
|
82 |
for ac in $fgaddon_path/*/*-set.xml; do |
|
83 |
ac=${ac/$fgaddon_path} |
|
84 |
sx=${ac##*/} |
|
85 |
ac=${ac%/*} |
|
86 |
if test -d $fgaddon_path/$ac/.svn; then |
|
87 |
install_type=1 |
|
88 |
elif test -d $fgaddon_path/$ac/.git; then |
|
89 |
install_type=2 |
|
90 |
else |
|
91 |
install_type=3 |
|
92 |
fi |
|
93 |
sqlite_request "update setxml set installed = $install_type |
|
94 |
where exists ( |
|
ré-écriture complète
|
95 |
select 1 |
96 |
from aircrafts |
|
97 |
where name = '${ac/\/}' and setxml.variantof = id |
|
many improvement
|
98 |
)" |
many improvements
|
99 |
done |
improve output for missing a...
|
100 |
missing_setxml=$(sqlite_request "select printf(' - %s', name) from aircrafts where id not in (select variantof from setxml)") |
ré-écriture complète
|
101 |
if test -n "$missing_setxml"; then |
improve output for missing a...
|
102 |
echo -e "missing setxml config for :\n$missing_setxml" |
ré-écriture complète
|
103 |
fi |
ajout de gestion de bdd pour...
|
104 |
if test -r "$database" && md5sum $in_ram_database | sed "s,$in_ram_database,$database," | md5sum --status -c -; then |
105 |
rm -f $in_ram_database |
|
many improvements
|
106 |
echo "no changes in $database" |
ajout de gestion de bdd pour...
|
107 |
elif test -w "$database"; then |
complete rewrite (use svn in...
|
108 |
sqlite_request "vacuum" |
ajout de gestion de bdd pour...
|
109 |
mv -f $in_ram_database "$database" |
many improvements
|
110 |
echo "database $database updated" |
ajout de gestion de bdd pour...
|
111 |
elif ! test -e "$database"; then |
112 |
mv $in_ram_database "$database" |
|
many improvements
|
113 |
echo "database $database created" |
ajout de gestion de bdd pour...
|
114 |
else |
115 |
rm -f $in_ram_database |
|
many improvements
|
116 |
echo "nothing can be done with $database !" |
ajout de gestion de bdd pour...
|
117 |
fi |
118 |
} |
|
119 | ||
ré-écriture complète
|
120 |
function register_state () { |
121 |
sqlite_request "drop table if exists recover_rev" |
|
122 |
sqlite_request "create table recover_rev ( |
|
123 |
revkey text, |
|
124 |
revision integer, |
|
125 |
revauthor text, |
|
126 |
revdate integer |
|
127 |
)" |
|
fix variable name conflict
|
128 |
for revkey in ${!revindex[@]}; do |
ré-écriture complète
|
129 |
sqlite_request "insert into recover_rev values ( |
130 |
'$revkey', |
|
fix variable name conflict
|
131 |
${revindex[$revkey]:-0}, |
ré-écriture complète
|
132 |
'${revauthor[$revkey]}', |
133 |
${revdate[$revkey]:-0} |
|
134 |
)" |
|
135 |
done |
|
136 |
sqlite_request "drop table if exists recover_setxmlmodified" |
|
137 |
sqlite_request "create table if not exists recover_setxmlmodified ( |
|
138 |
sx text |
|
139 |
)" |
|
140 |
for sx in ${!setxmlmodified[@]}; do |
|
141 |
sqlite_request "insert into recover_setxmlmodified values ( |
|
142 |
'$sx' |
|
143 |
)" |
|
144 |
done |
|
145 |
exit |
|
146 |
} |
|
147 | ||
148 |
function update_database () { |
|
fix variable name conflict
|
149 |
echo "[ ${#revindex[@]} ] ${ac:1}" |
ajout de gestion de bdd pour...
|
150 | |
ré-écriture complète
|
151 |
dbupdate=$(sqlite_request "select revision from aircrafts where name is '${ac:1}'") |
ajout de gestion de bdd pour...
|
152 |
if test -z "$dbupdate"; then |
complete rewrite (use svn in...
|
153 |
sqlite_request "insert into aircrafts (name, revision, date, author) |
fix variable name conflict
|
154 |
values ('${ac:1}', ${revindex[$ac]}, ${revdate[$ac]}, '${revauthor[$ac]}')" |
155 |
elif test $dbupdate -lt ${revindex[$ac]}; then |
|
complete rewrite (use svn in...
|
156 |
sqlite_request "update aircrafts set |
fix variable name conflict
|
157 |
revision = ${revindex[$ac]}, |
complete rewrite (use svn in...
|
158 |
author = '${revauthor[$ac]}', |
159 |
date = ${revdate[$ac]} |
|
ré-écriture complète
|
160 |
where name is '${ac:1}'" |
ajout de gestion de bdd pour...
|
161 |
fi |
ré-écriture complète
|
162 |
id=$(sqlite_request "select id from aircrafts where name is '${ac:1}'") |
ajout de gestion de bdd pour...
|
163 | |
ré-écriture complète
|
164 |
for sx in ${!setxmlmodified[@]}; do |
165 |
unset include include_rootpath |
|
166 |
[[ "$sx" =~ ^"${ac:1}/" ]] || continue |
|
167 |
for col in ${!data[@]}; do |
|
168 |
data[$col]= |
|
169 |
done |
|
170 |
sx=${sx#*/} |
|
remove -set.xml from filenam...
|
171 |
echo " -> $sx" |
ré-écriture complète
|
172 |
if ! svn export --quiet --force $fgaddon_svn/${ac:1}/$sx-set.xml $setxml; then |
173 |
register_state |
|
174 |
fi |
|
175 |
xmlremovecomments |
|
176 |
unset xmlgetnext_firstentry property |
|
complete rewrite (use svn in...
|
177 |
while xmlgetnext; do |
ré-écriture complète
|
178 |
case "${TAG:0:1}" in |
179 |
''|'?'|'!') |
|
180 |
continue;; |
|
181 |
/) |
|
182 |
property=${property%/*};; |
|
183 |
*) |
|
184 |
if test "${TAG: -1}" != '/'; then |
|
185 |
property+=/${TAG%% *} |
|
fix syntax mistake
|
186 |
fi;; |
ré-écriture complète
|
187 |
# property+=/${TAG%% *} |
188 |
# if test "${TAG: -1}" = '/'; then |
|
189 |
# _TAG=${TAG:0:-1} |
|
190 |
# test "${_TAG#* }" != "${_TAG}" && eval "${_TAG#* }" |
|
191 |
# property=${property%/*} |
|
192 |
# fi;; |
|
193 |
esac |
|
194 | ||
195 |
if [[ "$TAG" =~ ^"PropertyList include=" ]]; then |
|
196 |
include_rootpath=${include%/*} |
|
197 |
test $include = $include_rootpath && unset include_rootpath |
|
198 |
eval $(echo ${TAG#* }) |
|
199 |
[[ "$include" =~ ^Aircraft/Generic/ ]] && unset include include_rootpath && continue |
|
200 |
if [[ "$include" =~ ^'../' ]]; then |
|
201 |
if test -n "$include_rootpath"; then |
|
202 |
if [[ "$include_rootpath" =~ '/' ]]; then |
|
203 |
include_rootpath=${include_rootpath%/*} |
|
204 |
else |
|
205 |
unset include_rootpath |
|
206 |
fi |
|
207 |
else |
|
208 |
ac_save=$ac |
|
209 |
unset ac |
|
210 |
fi |
|
211 |
include=${include/\.\.\/} |
|
212 |
fi |
|
213 |
if ! svn cat $fgaddon_svn/${ac:1}/${include_rootpath:+$include_rootpath/}$include >> $setxml; then |
|
214 |
register_state |
|
215 |
fi |
|
216 |
xmlremovecomments |
|
217 |
fi |
|
218 | ||
219 |
if [[ "$property" = /PropertyList@($data_pattern) ]]; then |
|
fix overriding descs with in...
|
220 |
if test -z "${data[${property/\/PropertyList}]}"; then |
221 |
eval "data[${property/\/PropertyList}]=\"${VALUE//\"/\\\"}\"" |
|
222 |
data[${property/\/PropertyList}]=$(tr '\n' ' ' <<< ${data[${property/\/PropertyList}]} | sed -r 's/^\s*//;s/\s+/ /g;s/\s*$//') |
|
223 |
fi |
|
many improvement
|
224 |
fi |
ajout de gestion de bdd pour...
|
225 | |
small stuff
|
226 |
# if test -n "$_TAG"; then |
227 |
# # _TAG non-null means xml props ends with / |
|
228 |
# # need to go back of last property |
|
229 |
# property=${property/%\/${_TAG%% *}} |
|
230 |
# unset _TAG |
|
231 |
# fi |
|
many improvement
|
232 | |
ré-écriture complète
|
233 |
# continue parsing (while loop) until everything's found |
234 |
for col in ${!data[@]}; do |
|
235 |
test -z "${data[$col]}" && continue 2 |
|
236 |
done |
|
237 |
break # everything's found |
|
238 |
done < $setxml |
|
ajout de gestion de bdd pour...
|
239 | |
ré-écriture complète
|
240 |
if eval "test -z \"$data_test_null\""; then |
241 |
echo "WARNING: no info found, skipping" |
|
242 |
continue |
|
complete rewrite (use svn in...
|
243 |
fi |
244 | ||
ajout de gestion de bdd pour...
|
245 |
known=$(sqlite_request "select variantof from setxml where file is '$sx'") |
246 |
if test -n "$known"; then |
|
ré-écriture complète
|
247 |
for col in ${!data[@]}; do |
248 |
dbvalue=$(sqlite_request "select '$col' |
|
249 |
from setxml |
|
250 |
where file is '$sx' and variantof = $known") |
|
251 |
if test "$dbvalue" != "${data[$col]}" -a -n "${data[$col]}"; then |
|
252 |
sqlite_request "update setxml |
|
253 |
set '$col' = '${data[$col]//\'/\'\'}' |
|
254 |
where file is '$sx' and variantof = $known" |
|
ajout de gestion de bdd pour...
|
255 |
fi |
256 |
done |
|
257 |
else |
|
ré-écriture complète
|
258 |
values="'$sx', $id, " |
259 |
for col in ${!data[@]}; do |
|
260 |
values+="'${data[$col]//\'/\'\'}', " |
|
261 |
done |
|
262 |
values+=0 |
|
263 |
sqlite_request "insert into setxml values ($values)" |
|
264 |
fi |
|
265 |
test -n "$ac_save" && ac=$ac_save |
|
266 |
unset setxmlmodified[${ac:1}/$sx] |
|
267 |
done |
|
fix variable name conflict
|
268 |
unset revindex[$ac] |
ré-écriture complète
|
269 |
} |
270 | ||
271 |
function apply_revision () { |
|
fix variable name conflict
|
272 |
for ac in "${!revindex[@]}"; do |
ré-écriture complète
|
273 |
update_database |
274 |
if test -d $fgaddon_path/${ac:1}/.svn \ |
|
275 |
&& test "$(svn info --show-item=url $fgaddon_path/${ac:1})" != "$fgaddon_svn/${ac:1}" \ |
|
276 |
|| test -d $fgaddon_path/${ac:1} -a ! -d $fgaddon_path/${ac:1}/.svn; then |
|
277 |
echo "INFO: local ${ac:1} installed out from repo" >&2 |
|
ajout de gestion de bdd pour...
|
278 |
fi |
279 |
done |
|
280 |
} |
|
281 | ||
ré-écriture complète
|
282 |
trap trap_break INT |
ajout de gestion de bdd pour...
|
283 |
trap trap_exit EXIT |
284 | ||
ré-écriture complète
|
285 |
stty -echoctl |
286 | ||
fix variable name conflict
|
287 |
declare -A revindex revauthor revdate setxmlmodified files revpath |
ré-écriture complète
|
288 |
data_pattern=$(printf "%s|" ${!data[@]}) |
289 |
data_pattern=${data_pattern:0:-1} |
|
290 |
data_test_null=$(printf '${data[%s]}' ${!data[@]}) |
|
291 | ||
292 |
if test -e $database; then |
|
293 |
cp $database $in_ram_database |
|
294 |
sql_cols=$(sqlite_request "pragma table_info(setxml)" | awk -F'|' '{printf("%s %s ", $2, $3)}') |
|
295 |
script_cols="file text variantof integer " |
|
296 |
for col in ${!data[@]}; do |
|
297 |
script_cols+="$col ${data["$col"]} " |
|
298 |
done |
|
299 |
script_cols+="installed integer " # last space is important |
|
300 |
if test "$sql_cols" != "$script_cols"; then |
|
301 |
echo "ALERT: datbase version mismatch !" |
|
302 |
exit 1 |
|
303 |
fi |
|
304 |
if sqlite_request '.tables' | grep -q 'recover_' && test -z "$1"; then |
|
305 |
echo "recovering from previous saved state" |
|
fix variable name conflict
|
306 |
eval $(sqlite_request "select printf('revindex[%s]=%u;revauthor[%s]=%s;revdate[%s]=%u;', |
ré-écriture complète
|
307 |
revkey, revision, |
308 |
revkey, revauthor, |
|
309 |
revkey, revdate) |
|
310 |
from recover_rev") |
|
311 |
eval $(sqlite_request "select printf('setxmlmodified[%s]=1;', sx) |
|
312 |
from recover_setxmlmodified") |
|
313 |
sqlite_request "drop table recover_rev" |
|
314 |
sqlite_request "drop table recover_setxmlmodified" |
|
315 |
apply_revision |
|
316 |
exit |
|
317 |
fi |
|
318 |
fi |
|
319 | ||
320 |
sqlite_request "create table if not exists aircrafts ( |
|
321 |
id integer primary key, |
|
322 |
name text, |
|
323 |
revision integer, |
|
324 |
date integer, |
|
325 |
author text)" |
|
ajout de gestion de bdd pour...
|
326 | |
ré-écriture complète
|
327 |
sqlite_request "create table if not exists setxml ( |
328 |
file text, |
|
329 |
variantof integer, |
|
330 |
$(for col in ${!data[@]}; do printf "'%s' %s, " $col ${data[$col]}; done) |
|
331 |
installed integer)" |
|
ajout de gestion de bdd pour...
|
332 | |
search for next revision
|
333 |
latest_revision=$(( $(sqlite_request "select max(revision) from aircrafts") + 1 )) |
complete rewrite (use svn in...
|
334 | |
ré-écriture complète
|
335 |
# for debugging purpose |
336 |
if test -n "$2"; then |
|
337 |
ac=_${1%/*} |
|
fix variable name conflict
|
338 |
revindex[$ac]=1 |
ré-écriture complète
|
339 |
revdate[$ac]=0 |
340 |
revauthor[$ac]=foobar |
|
341 |
setxmlmodified[${ac:1}/${1#*/}]=1 |
|
342 |
set -x |
|
343 |
update_database |
|
344 |
set +x |
|
345 |
exit |
|
346 |
elif test -n "$1"; then |
|
347 |
ac=_${1%/*} |
|
fix variable name conflict
|
348 |
eval $(sqlite_request "select printf('revindex[_%s]=%s;revdate[_%s]=%i;revauthor[_%s]=%s;', |
ré-écriture complète
|
349 |
name, revision, |
350 |
name, date, |
|
351 |
name, author) |
|
352 |
from aircrafts |
|
353 |
where name = '${ac:1}'") |
|
354 |
setxmlmodified[${ac:1}/${1#*/}]=1 |
|
fix variable name conflict
|
355 |
if test -z "${revindex[$ac]}"; then |
ré-écriture complète
|
356 |
echo "aircraft ${ac:1} not found" |
357 |
rm $in_ram_database |
|
358 |
exit |
|
359 |
fi |
|
360 |
update_database |
|
361 |
exit |
|
362 |
fi |
|
363 | ||
complete rewrite (use svn in...
|
364 |
echo "downloading FGADDON history from revision ${latest_revision:-0}" |
365 |
svn log --revision ${latest_revision:-0}:HEAD --xml --verbose $fgaddon_svn > $aircrafts |
|
366 | ||
ré-écriture complète
|
367 |
total=$(grep -c '<logentry' $aircrafts) |
368 |
progress=0 |
|
369 | ||
370 |
echo parsing history |
|
371 | ||
complete rewrite (use svn in...
|
372 |
while xmlgetnext; do |
373 |
case "$TAG" in |
|
374 |
'logentry revision='*) |
|
375 |
eval $(echo ${TAG#* }) |
|
ré-écriture complète
|
376 |
for action in ${!revpath[@]}; do |
377 |
unset revpath[$action] |
|
378 |
done |
|
complete rewrite (use svn in...
|
379 |
;; |
380 |
'author') |
|
ré-écriture complète
|
381 |
revauthor=${VALUE//\'/\'\'} |
complete rewrite (use svn in...
|
382 |
;; |
383 |
'date') |
|
384 |
revdate=$(date +%s -d "$VALUE") |
|
385 |
;; |
|
386 |
'path '*) |
|
ré-écriture complète
|
387 |
TAG=${TAG#* } |
388 |
TAG=${TAG// /;} |
|
389 |
TAG=${TAG//-/_} |
|
390 |
eval $(echo ${TAG// /;}) |
|
391 |
path=(${VALUE//\// }) |
|
392 |
if test $kind = 'file' -a ${#path[@]} -gt 3; then |
|
393 |
revpath[$action]+="$VALUE " |
|
394 |
elif test $kind = 'dir' -a ${#path[@]} -eq 3 -a $action = 'D'; then |
|
395 |
files[_${path[2]}]=0 |
|
fix variable name conflict
|
396 |
unset revindex[_${path[2]}] revauthor[_${path[2]}] revdate[_${path[2]}] |
ré-écriture complète
|
397 |
for sx in ${!setxmlmodified[@]}; do |
398 |
[[ "$sx" =~ "${path[2]}/" ]] && unset setxmlmodified[$sx] |
|
399 |
done |
|
400 |
fi |
|
complete rewrite (use svn in...
|
401 |
;; |
402 |
'/logentry') |
|
ré-écriture complète
|
403 |
for item in ${revpath[D]}; do |
404 |
path=(${item//\// }) |
|
manage aircraft deletion
|
405 |
if [[ "${path[3]}" =~ "-set.xml" ]]; then |
406 |
unset setxmlmodified[${path[2]}/${path[3]/-set.xml}] |
|
407 |
sqlite_request "delete from setxml where file = '${path[3]/-set.xml}'" |
|
408 |
fi |
|
ré-écriture complète
|
409 |
files[_${path[2]}]=$(( --files[_${path[2]}] )) |
410 |
if test ${files[_${path[2]}]} -le 0; then |
|
fix variable name conflict
|
411 |
unset revindex[_${path[2]}] revauthor[_${path[2]}] revdate[_${path[2]}] |
manage aircraft deletion
|
412 |
sqlite_request "delete from aircrafts where name = '${path[2]}'" |
many improvement
|
413 |
fi |
complete rewrite (use svn in...
|
414 |
done |
ré-écriture complète
|
415 |
for action in A M R; do |
416 |
for item in ${revpath[$action]}; do |
|
417 |
path=(${item//\// }) |
|
fix variable name conflict
|
418 |
revindex[_${path[2]}]=$revision |
ré-écriture complète
|
419 |
revauthor[_${path[2]}]=$revauthor |
420 |
revdate[_${path[2]}]=$revdate |
|
421 |
[[ "${path[3]}" =~ "-set.xml" ]] && setxmlmodified[${path[2]}/${path[3]/-set.xml}]=1 |
|
422 |
test $action = 'A' && files[_${path[2]}]=$(( ++files[_${path[2]}] )) |
|
423 |
done |
|
424 |
done |
|
425 |
newprogress=$((++logentry * 100 / $total)) |
|
426 |
if test $(( $newprogress - $progress )) -ge ${progress_granularity:-1}; then |
|
427 |
progress=$newprogress |
|
fix variable name conflict
|
428 |
echo "$progress% (${#revindex[@]})" |
ré-écriture complète
|
429 |
fi |
430 |
;; |
|
431 |
'/log') |
|
432 |
apply_revision |
|
complete rewrite (use svn in...
|
433 |
break |
434 |
;; |
|
435 |
esac |
|
436 |
done < $aircrafts |