Как уже упоминал Шили , сценарий оболочки bash (который выглядит очень похоже) не допускает пустых блоков между , если
и либо else
, elif
или fi
, или между else
или elif
и соответствующими fi
. (Это сводится к следующему: каждое условное выражение должно делать что-то.)
Вы можете либо удалить оператор else
, либо, если хотите, чтобы это было позже, поместите в него фиктивную команду блок else
. Например, вы можете переписать свой сценарий следующим образом:
case $# in
0) echo Usage is: $0 filename [filename]
exit;;
*);;
esac
for i in $*
do
if test -f $i;
then
echo $i
cat $i
else
true
fi
done
(Я также сделал отступ fi
, чтобы он соответствовал if
. Это вопрос стиля, но я лично считаю его гораздо легче читать таким образом.)
true
имеет своей единственной целью вернуть успешный статус выхода, но это команда, поэтому этот сценарий ничего не сделает, если имя в $ i
не относится к простому файлу ( test -f
).
Некоторые идеи:
"Параметрическое расширение" значения переменной (часть ${...}):
echo "arr$COUNTER[0] = ${arr$COUNTER[0]}"
не сработает. Вы можете обойтись использованием eval (но я не рекомендую это делать):
eval echo "arr$COUNTER[0] = \${arr$COUNTER[0]}"
Эту строку можно написать так:
i="arr$COUNTER[0]"; echo "$i = ${!i}"
В Bash это называется перенаправлением (символ !).
Аналогичная проблема возникает с этой строкой:
declare -a "arr$COUNTER=($field)"
Которую следует разделить на две строки и использовать eval:
declare -a "arr$COUNTER"
eval arr$COUNTER\=\( \$field \)
Опять же, я не рекомендую использовать eval (в данном случае).
Поскольку вы читаете весь файл в память оболочки, мы можем использовать более простой метод, чтобы получить все строки в массив:
readarray -t lines <"VALUES_FILE.txt"
Это должно быть быстрее, чем вызов awk для каждой строки.
Сценарий со всем вышеперечисленным может быть таким:
#!/bin/bash
valfile="VALUES_FILE.txt"
readarray -t lines <"$valfile" ### read all lines in.
line_count="${#lines[@]}"
echo "Total number of lines $line_count"
for ((l=0;l<$line_count;l++)); do
echo "Counter value is $l" ### In which line are we?
echo "Field = ${lines[l]}" ### kepth only to help understanding.
k="arr$l" ### Build the variable arr$COUNTER
IFS=" " read -ra $k <<<"${lines[l]}" ### Split into an array a line.
eval max=\${#$k[@]} ### How many elements arr$COUNTER has?
#echo "field $field and k=$k max=$max" ### Un-quote to "see" inside.
for ((j=0;j<$max;j++)); do ### for each element in the line.
i="$k[$j]"; echo "$i = ${!i}" ### echo it's value.
done
done
echo "The End"
echo
Однако, все же AWK может быть быстрее, если мы сможем выполнить то, что вам нужно в AWK.
Аналогичная обработка может быть выполнена в awk. Предположим, что 6 значений будут использоваться в качестве IP (4 из них), а два других - это число и время эпохи.
Просто очень простой пример скрипта AWK:
#!/bin/sh
valfile="VALUES_FILE.txt"
awk '
NF==6 { printf ( "IP: %s.%s.%s.%s\t",$1,$2,$3,$4)
printf ( "number: %s\t",$5+2)
printf ( "epoch: %s\t",$6)
printf ( "\n" )
}
' "$valfile"
Просто создайте новый вопрос с подробностями.
Вы можете генерировать имена, используя eval
, например,
eval declare -a '"arr'$COUNTER'=($field)"'
по существу цитируя все метасимволы, кроме тех, которые вы хотите оценить.
Итак ... если $ COUNTER
равно 1, ваш сценарий будет выполнять
declare -a "arr1=($field)"
Дополнительная информация:
Вы можете использовать косвенное обращение к переменной, если присвоите переменной имя и индекс:
s="arr$COUNTER[0]"
echo "arr$COUNTER[0] = ${!s}"
Стандартный способ хранения данных многомерного -массива в массиве размерности 1 заключается в сохранении каждой строки со смещением в массиве.
Элемент (i,j)
будет располагаться по индексу i*m + j
, где i
— индекс строки на основе нуля -, j
— индекс столбца на основе нуля -, а m
— количество столбцы.
Это также упрощает чтение данных, поскольку мы можем просто взять ваш входной файл, изменить все пробелы на новые строки и использовать readarray
.
В командной строке:
$ readarray -t arr < <( tr -s ' ' '\n' <data )
$ printf '%s\n' "${arr[@]}"
10
20
30
40
50
60
100
200
300
400
500
600
Мы можем определить количество столбцов в данных с помощью
$ m=$( awk '{ print NF; exit }' <data )
И количество рядов:
$ n=$( wc -l <data )
Затем мы можем перебирать столбцы и строки в двойном цикле, как обычно:
for (( i = 0; i < n; ++i )); do
for (( j = 0; j < m; ++j )); do
printf '%4d' "${arr[i*m + j]}"
done
printf '\n'
done
Для заданных данных это будет генерировать
10 20 30 40 50 60
100 200 300 400 500 600
В идеале вы должны использовать язык, такой как Perl, Python или C, который поддерживает многомерные -массивы. То есть, если вам действительно нужно хранить весь набор данных в памяти вообще и вы не можете обрабатывать его построчно.
Для построчной обработкиawk
будет хорошим кандидатом на заменуbash
(любой язык будет хорошим кандидатом на замену оболочки для любого вида обработки данных):
awk '{ for (i = 1; i <= NF; ++i) printf("%4d", $i); printf("\n") }' data