#arrays #bash #shell
#массивы #bash #оболочка
Вопрос:
Я написал скрипт bash, который считывает файл из stdin $ 1, и ему нужно прочитать этот файл построчно в цикле, и на основе инструкции условия на каждой итерации каждая проверенная строка из файла будет передаваться в один из двух новых массивов, скажем, с именами GOOD array и BAD array. Наконец, я выведу общее количество элементов каждого массива.
#!/bin/bash
for x in $(cat $1); do
#testing something on x
if [ $? -eq 0 ]; then
#add the current value of x into array called GOOD
else
#add the current value of x into array called BAD
fi
done
echo "Total GOOD elements: ${#GOOD[@]}"
echo "Total BAD elements: ${#BAD[@]}"
Какие изменения я должен внести, чтобы выполнить это?
Комментарии:
1.
for x in $(cat ...anything...)
является антипаттером. Смотрите в BashFAQ # 1 рекомендации по итерации содержимого файла.2. Ваш вопрос звучит так: «Пожалуйста, сделайте за меня мою домашнюю работу». Чтобы улучшить свой вопрос, укажите, каков результат, что вы пробовали и что конкретно вы пытаетесь исправить.
3. Хотя я ответил на этот вопрос, я согласен, что в настоящее время это не тот вопрос, к которому мы стремимся здесь. Идеальный вопрос был бы более узким — скажем, «как мне добавить к массиву в bash?» (хотя это дубликат) или «почему чтение из файла с
for word in $(cat $1)
глобусами расширения, когда я этого не хочу?» (хотя это тоже дубликат); с самым коротким кодом, необходимым для иллюстрации этого единственного, конкретного, узкого вопроса.4. Спасибо @CharlesDuffy за вашу помощь, мы признательны. Массивы в bash для меня немного неоднозначны, я уже просмотрел 3 курса по написанию сценариев на bash, прежде чем задать этот вопрос. Простите, что задаю вопрос, но это мой первый раз, и впредь я буду его улучшать.
5. @MoatazOsama : Ваш скрипт обрабатывает ввод не построчно, а слово за словом. Кроме того, я не понимаю, что
[ $? ... ]
предполагается делать.$?
это код состояния самой последней выполненной команды.
Ответ №1:
#!/usr/bin/env bash
# here, we're checking the number of lines more than 5 characters long
# replace with your real test
testMyLine() { (( ${#1} > 5 )); }
good=( ); bad=( )
while IFS= read -r line; do
if testMyLine "$line"; then
good =( "$line" )
else
bad =( "$line" )
fi
done <"$1"
echo "Read ${#good[@]} good and ${#bad[@]} bad lines"
Примечание:
- Мы используем
while read
цикл для перебора содержимого файла. При этом не требуется считывать в память более одной строки за раз (поэтому оперативная память не будет исчерпана даже при работе с действительно большими файлами), и у него нет нежелательных побочных эффектов, таких как изменение строки, содержащей*
список файлов в текущем каталоге. - Мы не используем
$?
.if foo; then
это гораздо лучший способ ветвления по статусу выходаfoo
, чемfoo; if [ $? = 0 ]; then
— в частности, это позволяет избежать зависимости от значения$?
not being changed между тем, когда вы его назначаете, и тем, когда оно вам нужно; и оно помечаетсяfoo
как «проверено», чтобы избежать выхода черезset -e
или срабатывания ловушки ошибок, когда ваше логическое значение возвращает false . - Имена переменных в нижнем регистре используются намеренно. Имена в верхнем регистре используются для встроенных в оболочку переменных и имен, имеющих особое значение для операционной системы — и поскольку определение обычной переменной оболочки перезаписывает любую переменную среды с тем же именем, это соглашение применимо к обоим типам. Смотрите http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html