Как выполнить итерации более чем двух наборов iterables в сценарии оболочки?

В системных вызовах существует на самом деле три градации.

  1. Некоторые системные вызовы сразу возвращаются. “Сразу” означает, что единственной вещью, в которой они нуждаются, является немного процессорного времени. Нет никакого жесткого предела тому, сколько времени они могут взять (кроме систем реального времени), но эти вызовы возврат, как только они были запланированы довольно долго.
    Эти вызовы обычно называют, не блокируясь. Примерами неблокирования вызовов являются вызовы, которые просто читают немного состояния системы или вносят простое изменение в состояние системы, такой как getpid, gettimeofday, getuid или setuid. Некоторые системные вызовы могут блокироваться или не блокироваться в зависимости от обстоятельств; например, read никогда блоки, если файл является каналом или другим типом, который поддерживает неблокирующиеся чтения и O_NONBLOCK флаг установлен.
  2. Несколько системных вызовов могут требовать времени к полному, но не навсегда. Типичный пример sleep.
  3. Некоторые системные вызовы не возвратятся, пока некоторый внешний случай не происходит. Эти вызовы, как говорят, блокируются. Например, read обращенный блокирующийся дескриптор файла блокируется и так wait.

Различие между “быстрыми” и “медленными” системными вызовами близко к неблокированию по сравнению с блокированием, но на этот раз с точки зрения реализатора ядра. Быстрый syscall является тем, который, как известно, может завершиться, не блокируясь или ожидая. Когда ядро встречается с быстрым syscall, оно знает, что может сразу выполнить syscall и сохранить тот же процесс запланированным. (В некоторых операционных системах с невытесняющей многозадачностью быстрый syscalls может быть неприоритетным; дело обстоит не так в нормальных системах Unix.), С другой стороны, медленный syscall потенциально требует ожидания другой задачи завершиться, таким образом, ядро должно подготовиться приостанавливать обработку вызовов и выполнять другую задачу.

Некоторые случаи являются чем-то вроде серой области. Например, чтение с диска (read из регулярного файла), обычно рассматривается, не блокируясь, потому что он не ожидает другого процесса; это только ожидает диска, который обычно занимает только немного времени для ответа, но не возьмет навсегда (таким образом, это - случай 2 выше). Но с точки зрения ядра, процесс должен ожидать дискового драйвера для завершения, таким образом, это - определенно медленный syscall.

3
25.08.2011, 12:39
4 ответа

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

n=0
for x in $commands; do
  mv -- "$x" "$n.jpg"
  n=$(($n+1))
done

Обратите внимание, что это только работает, если ни один из элементов, которых Вы выполняете итерации, не содержит пробела (ни globbing символы). Если Вам разделили объекты новые строки, выключаете globbing и разделяете только на новых строках.

n=0
IFS='
'; set -f
for x in $commands; do
  mv -- "$x" "$n.jpg"
  n=$(($n+1))
done
set +f; unset IFS

Если только необходимо выполнить итерации по данным однажды, цикл вокруг read (см., Почему while IFS= read используемый так часто, вместо IFS=; while read..? для большего количества объяснений).

n=0
while IFS= read -r x; do
  mv -- "$x" "$n.jpg"
  n=$(($n+1))
done <<EOF
…
EOF

При использовании оболочки, которая имеет массивы (удар, ksh или zsh), сохраните элементы в массиве. В zsh, любом выполнении setopt ksh_arrays к элементам массива числа от 0, или адаптируют код к нумерации элемента массива, запускающейся в 1.

commands=(
    ./01/IMG0000.jpg
    …
)
n=0
while [[ $n -lt ${#commands} ]]; do
  mv -- "${commands[$n]}" "$n.jpg"
done
5
27.01.2020, 21:13

Если Ваша оболочка bash, Вы не должны работать seq программа. Просто используйте

for i in {1..736}
  do

Если Вы хотите последовательность с начальными нулями, просто используйте {001..736} (или даже {0001..0736}) вместо этого.

Кроме того, если это возможно, попытайтесь не использовать обратные галочки (см. этот вопрос для того, как он может испортить вещи).

Другая вещь, когда Вы хотите воздействовать на ряд файлов, Вы могли бы найти это полезным:

for file in /some/path/*
  do

Который будет воздействовать на все файлы (и папки) в каталоге /some/path/. Для сужения этого к файлам только можно использовать тест как [ -f "$file" ], например,

for file in /some/path/*
  do
  [ -f "$file" ] || continue
  (do your stuff here)

Кроме того, конструкция /some/path/* может быть настроен шаблонами оболочки как /some/path[123]/*, /some/path[A-Z]/b*[e-g]*, /some/path{1,5,23}/* и т.д.

Что касается первой части Вашего вопроса, можно просто использовать вложенный for (или while или любой) цикл как это:

for cm in $commands; do
 for file in /some/path[ab]{1,4,2}/*.log; do
    mv "${file}" "${file//text/replacement}"
 done
done
3
27.01.2020, 21:13

Я не думаю, что можно выполнить итерации по нескольким вещам параллельно в ударе.

Я начал бы i=1. затем выполните итерации по своему списку файлов и включайте let i=$i+1 в цикле. Также включайте тест для убегания из цикла если $i -ge 736 если Вы хотите выйти из итерации по тому, что Ваш вход после того количества циклов.

i=0
for file in ./{01..10}/*jpg; do
    let i=$i+1
    mv "$file" "$i-$file"
done

Если бы Вы пытались вполне то после X количества файлов Вы могли бы использовать тест как это:

[[ $i -ge 736 ]] && return || let i=$i+1
3
27.01.2020, 21:13

удар поддерживает массивы:

http://tldp.org/LDP/abs/html/arrays.html

ИЛИ

COUNT=0
for i in `ls *.txt`
do
  COUNT=`expr $COUNT + 1`
  mv "$i" "$COUNT-$i"
done

Это переименовало бы файлы a.txt b.txt c.txt к 1-a.txt 2-b.txt 3-c.txt.

-4
27.01.2020, 21:13
  • 1
    Можно ли дать демонстрацию того, как массивы могли сделать эту особенно пишущую сценарий проблему легче / быстрее / более изящный? –  Caleb 23.08.2011, 17:56
  • 2
    Не анализируйте вывод ls как этот! Оболочка globing обработает это правильно, с помощью ls повредит его! –  Caleb 23.08.2011, 18:16
  • 3
    При использовании удара этот подход к постепенному увеличению переменной может быть сделан в оболочке: (( COUNT++ )) –  glenn jackman 23.08.2011, 18:46
  • 4
    Примером, о котором сообщают, является одна из причины избегать ABS. –  enzotib 23.08.2011, 22:37
  • 5
    Нет, Caleb прав. Не анализируйте вывод ls.Это не работает. Кроме того, если Вы не работаете на старинных вещах, используйте арифметику оболочки, Вам не нужно expr больше. –  Gilles 'SO- stop being evil' 24.08.2011, 01:29

Теги

Похожие вопросы