LINUX.ORG.RU

Foreach в командной строке

 


1

3

Какой способ последовательного вызова одной и той же команды для каждой строки из текста наилучший? Про циклы for в баше мне известно, но может есть более короткое для записи решение?

★★★★★
Ответ на: комментарий от next_time

readarray

Ну да, повторяться не буду.

readarray array <<< "$(ls .. -n)"

Вы это хотя бы проверяли прежде, чем сюда послать? Hint: -t.

И сугубо по идиоматике:

<<< "$(...)"

< <(...) чем-то не устроила?

for ((i = 0 ; i < ${#array[@]} ; i++ ))

Вам нужно оперировать именно индексом? Если перебор элементов массива: for f in "${array[@]}", то перебор индексов: for f in ${!array[@]}. Впрочем, не берусь утверждать, что что-нибудь из этого лучше.

Zmicier ★★★★★
()
Ответ на: комментарий от Zmicier

Впрочем, не берусь утверждать, что что-нибудь из этого лучше.

И правильно, что не берётесь. Это же не C с указателями. f - будет просто копия элемента массива, потому это не всегда удобно, когда надо сам элемент изменить/удалить.

vodz ★★★★★
()
Ответ на: комментарий от vodz

Это же не C с указателями. f - будет просто копия элемента массива

Или таки индекс. Там, как вы заметили, два варианта. И в обоих f, ибо я не поменял его на i (хотя, наверное, надо было).

Zmicier ★★★★★
()
Последнее исправление: Zmicier (всего исправлений: 1)
Ответ на: комментарий от Deleted

В КОИ8-Р твой говнофайл будет хрен знает как отображаться!

Зачем мучить себя и того, кто у тебя этот файл скопировать захочет?

anonymous
()
Ответ на: комментарий от Zmicier

Там, как вы заметили, два варианта.

Ох, опять как обычно, бегом отвечать не вчитываясь. А это ничего, что у меня и было два варианта? Запись for f in ${!array[@]} статична, при удалении будет лишние циклы.

vodz ★★★★★
()
Ответ на: комментарий от anonymous

В моей говноКОИ8-Р твой файл будет хрен знает как отображаться!

Пофиксил, не благодари.

Зачем мучить себя и того, кто у тебя этот файл скопировать захочет?

Зачем мучить себя кодировками не просто устаревшими, так еще и ненужными сразу с момента своего изобретения? А передатчики системы Маркони у тебя, случайно, не сохранились?

Deleted
()
Ответ на: комментарий от vodz

Ох, опять как обычно, бегом отвечать не вчитываясь.

Ничего страшного. :-) Не вы один, здесь все так делают.

Запись for f in ${!array[@]} статична, при удалении будет лишние циклы.
лишние

По сравнению с чем?

Zmicier ★★★★★
()
Последнее исправление: Zmicier (всего исправлений: 1)
Ответ на: комментарий от anonymous

У адекватных людей koi8 отмерла в 2002 году с выходом redhat 8. 15 лет назад.

Если кто-то застрял там это его проблемы.

pawnhearts ★★★★★
()
Ответ на: комментарий от anonymous

Зачем мучить себя и того, кто у тебя этот файл скопировать захочет?

Сегодня я узнал, чем обусловлен такой бугурт от юникода у пользователей кои.

goingUp ★★★★★
()
Ответ на: комментарий от goingUp

Можно подумать, их там насильно держат и по рукам бьют, когда они пытаются локаль сменить.

Deleted
()
Ответ на: комментарий от Zmicier

По сравнению с чем?

Сравнение в C-style for-е происходит на каждой итерации, потому сверка с ${#array[@]} даст верное количество итераций в том числе и при удалении элементов. Ну да, i придётся декрементировать при удалении. Отсюда вытекает, что вообще запись for var in ... хороша для статического набора строк и небольшого их количества, а не то что C-style for-ы это придумано для неосиляторов bash-а, пришедших с C-программинга.

vodz ★★★★★
()
Ответ на: комментарий от pawnhearts

Это у потреблядей она отмерла, как только хрюникод придумали.

А адекватные люди пользуются адекватными кодировками.

anonymous
()
Ответ на: комментарий от Deleted

И как ты предлагаешь определить, сколько выделить памяти под хранение, скажем, страницы текста на три с половиной тысячи символов? В КОИ8 я выделю 3501 байт, и буду счастлив. А в хрюникоде ты как это определишь?

Ну и много другой гадости эта говнокодировка привносит.

Я не против хрюникода в GUI — в GUI сейчас какое только дерьмище не тащат (хоть те же культяпки с говнотыками), но в консоли хрюникоду места нет!

anonymous
()
Ответ на: комментарий от anonymous

И как ты предлагаешь определить, сколько выделить памяти под хранение, скажем, страницы текста на три с половиной тысячи символов? В КОИ8 я выделю 3501 байт, и буду счастлив. А в хрюникоде ты как это определишь?

Динамически распределять память должны были научить на первом курсе в университе.

А адекватные люди пользуются адекватными кодировками.

Сказал человек, не могущих обработать даже пробелы в именах файлов.

Deleted
()
Ответ на: комментарий от vodz

Сравнение в C-style for-е происходит на каждой итерации, потому сверка с ${#array[@]} даст верное количество итераций в том числе и при удалении элементов.

Понятно. Однако вы ошибаетесь.

Перебирать массив, из которого что-то удалили (или который изначально был разреженным), так, как вы предлагаете, вообще нельзя — ${#arr[@]} же это именно длина массива, а не номер его последнего элемента.

$ arr=([0]=a [3]=d)
$ echo ${#arr[@]}
2
$ for ((i = 0; i < ${#arr[@]}; i++)); do echo "arr[$i] == ${arr[$i]}"; done
arr[0] == a
arr[1] == 

А можно только так:

$ for i in ${!arr[@]}; do echo "arr[$i] == ${arr[$i]}"; done
arr[0] == a
arr[3] == d
Zmicier ★★★★★
()
Ответ на: комментарий от Zmicier

Разреженные массивы в любом языке требуют специального обращения ибо они придуманы не для баловства, а для специальных задач. Данный топик их не требует. А у вас очередное верчение попой. Вы в цикл вставьте unset arr[ i ], а потом уже попытайтесь объяснить кто тут ошибается.

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)
Ответ на: комментарий от vodz

Разреженные массивы ... придуманы не для баловства, а для специальных задач. Данный топик их не требует.

Бинго! Зачем же вы про них вспомнили? В который раз сумничать не по делу захотели?

Вы в цикл вставьте unset arr[ i ], а потом уже...

Ну, если вы не в силах, что ж — не баре, давайте за вас сделаем. Итак, по vodz’у:

$ arr=(a b c d)
$ for ((i = 0; i < ${#arr[@]}; i++)); do echo "arr[$i] == ${arr[$i]}"; unset arr[$i]; done
arr[0] == a
arr[1] == b
$ declare -p arr
declare -a arr=([2]="c" [3]="d")

Корректно:

$ arr=(a b c d)
$ for i in ${!arr[@]}; do echo "arr[$i] == ${arr[$i]}"; unset arr[$i]; done
arr[0] == a
arr[1] == b
arr[2] == c
arr[3] == d
$ declare -p arr
declare -a arr=()

А у вас очередное верчение попой.

Ой, все. Этот vodz слился, несите следующего.

Zmicier ★★★★★
()
Ответ на: комментарий от Zmicier

Зачем же вы про них вспомнили? В который раз сумничать не по делу захотели?

С фига ли не по делу? На входе миллионы строк, на выходе — нужные. Ваш цикл развернётся в миллион строк, сожрёт уйму памяти и времени.

Итак, по vodz’у:

Не надо выдумывать за других код. Не так. Нижеприведенный код удаляет строки начинающиеся с 'b' или 'c'.

j=0
arr=(a b c d)
for ((i = 0; i < ${#arr[@]}+j; i++)); do
        if [[ -z "${arr[i]#[bc]}" ]]; then
                arr_del[j++]=${arr[i]}
                unset arr[$i]
        fi
done
declare -p arr arr_del

declare -a arr='([0]=«a» [3]=«d»)' declare -a arr_del='([0]=«b» [1]=«c»)'

Вот когда уже осталось пару строк с разреженным массивом, то его уже придётся через ${!arr[ * ]}, но возможно понадобится только arr_del, он не разреженный.

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 2)
Ответ на: комментарий от vodz

С фига ли не по делу?

«Запись for f in ${!array[@]} статична, при удалении [элементов] будет лишние циклы» — vodz.

«Разреженные массивы ... придуманы не для баловства, а для специальных задач. Данный топик их не требует» — снова vodz.

Не надо выдумывать за других код.

Вы уж там определитесь: «вы в цикл вставьте unset arr[i]» или «не надо выдумывать»?

for ((i = 0; i < ${#arr[@]}+j; i++)); do ... j++ ...; done

Ну да, надо признаться, до подкручивания предела цикла for в теле цикла, я бы не додумался. Лол.

Нижеприведенный код удаляет строки начинающиеся с 'b' или 'c'.
[[ -z "${arr[i]#[bc]}" ]]

Никак нет.

*Равные* 'b' или 'с'. Если начинающиеся, то [[ -z "${arr[i]%[bc]*}" ]]. А если еще и по-нормальному, то [[ ${arr[i]} == [bc]* ]].

На входе миллионы строк, на выходе — нужные. Ваш цикл развернётся в миллион строк

Ну а что поделаешь, если зачем-то надо считывать все в память, а не обрабатывать построчно?

сожрёт уйму памяти и времени

Во-первых, полагаю, что если расход памяти причиняет неудобства, то принципиальная ошибка была сделана еще на этапе выбора языка.

А во-вторых, не сожрет он больше времени, даже меньше.

$ awk 'BEGIN { for (i = 0; i < 10**5; i++) printf ("%x\n", i) }' > test.in
$ cat test
#!/bin/bash

readarray -t arr < "$1"
declare -a arr_del

j=0
for ((i = 0; i < ${#arr[@]}+j; i++)); do
    if [[ ${arr[i]} == [bc]* ]]; then
        arr_del[j++]=${arr[i]}
        unset 'arr[$i]'
    fi
done

echo "${#arr[@]}"
echo "${#arr_del[@]}"

$ time ./test test.in
91262
8738

real	0m12.593s
user	0m12.532s
sys	0m0.040s

$ cat test
#!/bin/bash

readarray -t arr < "$1"
declare -a arr_del

for i in ${!arr[@]}; do
    if [[ ${arr[i]} == [bc]* ]]; then
       arr_del+=(${arr[i]})
       unset 'arr[$i]'
    fi
done

echo "${#arr[@]}"
echo "${#arr_del[@]}"

$ time ./test test.in
91262
8738

real	0m11.861s
user	0m11.792s
sys	0m0.044s
Zmicier ★★★★★
()
Последнее исправление: Zmicier (всего исправлений: 1)
Ответ на: комментарий от Zmicier

«Запись for f in ${!array[@]} статична, при удалении [элементов] будет лишние циклы» — vodz.

Именно. Если перезаписывать в array только нужные элементы, то выходной цикл мы можем сделать по счётчику полученных элементов, а ${!array[@]} же даст в том числе незатёртые.

«Разреженные массивы ... придуманы не для баловства, а для специальных задач. Данный топик их не требует» — снова vodz.

Именно. Разреженные массивы тут не требуются. Это вы их сюда подогнали. Вот с себя и спрашивайте.

arr=(a b c d)
for ((j = i = 0, n=${#arr[@]}; i < n; i++)); do
        if [[ "${arr[i]#[bc]}" == "${arr[i]}" ]]; then
                arr[j++]=${arr[i]}
        else
                unset arr[$i]
        fi
done
#
for ((i = j; i < n; i++)); do
        unset arr[$i]
done
# OR:
#for ((i = j; i < j; i++)); do
#        USE arr[$i]
#done

Результат - последовательно заполненый массив с нужными элементами. В коментариях — альтернатива, удобно и практично.

Ну да, надо признаться, до подкручивания предела цикла for в теле цикла, я бы не додумался. Лол.
Никак нет. *Равные* 'b' или 'с'.

Ну да, а я и не знал. Лол.

Ну а что поделаешь, если зачем-то надо считывать все в память, а не обрабатывать построчно?

Причём тут считывать, если речь конкретно о конструкции for var in ${arr[ * ]}?

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)
Ответ на: комментарий от Zmicier

Вы это хотя бы проверяли прежде, чем сюда послать?

это рабочий код

Вам нужно оперировать именно индексом?

просто привычка из С и С++

next_time ★★★★★
() автор топика
Ответ на: комментарий от next_time

Вам нужно оперировать именно индексом?

просто привычка из С и С++

Это хорошая проивычка. Я нешёл время и прогнал на тестовом файле Zmicier 0.1М строк с тремя вариантами цикла:

#!/bin/bash

readarray -t arr < "$1"
declare -i i j n

for((j=${#arr[@]},n=i=0;i<j;i++)); do
    [[ -z ${arr[i]##[bc]*} ]] && arr[n++]=${arr[i]}
done

echo "$n"
#!/bin/bash

readarray -t arr < "$1"
declare -i i n

n=0
for i in ${!arr[@]}; do
    [[ "${arr[i]}" == [bc]* ]] && arr[n++]=${arr[i]}
done

echo "$n"
#!/bin/bash

readarray -t arr < "$1"
declare -i n=0

for i in "${arr[@]}"; do
    [[ -z ${i##[bc]*} ]] && arr[n++]=$i
done

echo "$n"
По времени:
real    0m6.943s
user    0m6.817s
sys     0m0.083s

real    0m6.377s
user    0m6.302s
sys     0m0.079s

real    0m1.468s
user    0m1.395s
sys     0m0.058s
По памяти
VSZ     RSS
30868 20228
68272 57792
68368 57792
То есть самый быстрый способ по значениям, а C-style по индексам - самый медленный. Но, вот памяти не C-style жрут как ни странно одинаково, но плюс 37.7 Мегабайт! То что по C-style-индексам медленно показывает, что bash не очень то заботится о оптимизации циклов, а выполняет их тупо. Но так как разница по индексам и по C-style-индексам всего 10%, а по памяти в выделении памяти на весь массив перед выполнением цикла, то получается, что C-style-индексы самый лучший вариант.

Но даже не это важно, а то, что после этого теста в результате получится массив, с которым можно работать только по C-style-индексам.

vodz ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.