Как читать из двух входных файлов с помощью цикла с условием продолжения

Благодаря ответу DarwinSurvivor я смог лучше понять, как управление пакетом работает в Arch. Теперь я могу применить ту же стратегию, которую я использую с хинду (с маленькими модификациями). "Эквиваленты" команд в вопросе, соответственно:

  1. pacman -S
  2. pacman -D --asdeps
  3. pacman -Rs $(pacman -Qqtd)
  4. Не доступный / не нужный

Самая близкая вещь к /var/lib/portage/world в хинду результат команды pacman -Qe. Различия:

  1. Дуга имеет группы пакета, который является в основном несколькими пакетами, "сгруппированными" вместе под именем. Когда группа установлена, все в группе считают явно установленным.
  2. Дуга не имеет "системных пакетов", таким образом уменьшая объекты от результата pacman -Qe может на самом деле привести к важным удаляемым пакетам.

27
12.12.2011, 03:14
5 ответов

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

Пример вставки с помощью вкладки разделителя по умолчанию:

paste file1 file2 | while IFS="$(printf '\t')" read -r f1 f2
do
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done

Пример использования вставки @:

paste -d@ file1 file2 | while IFS="@" read -r f1 f2
do
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done

Обратите внимание, что это достаточно, если символ, как гарантируют, не произойдет в первом файле. Это вызвано тем, что read проигнорирует IFS при заполнении последней переменной. Итак, даже если @ происходит во втором файле, он не будет разделен.

Пример вставки, использующей некоторые функции удара для возможно более чистого кода:

while IFS=$'\t' read -r f1 f2
do
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done < <(paste file1 file2)

Функции Bash использовали: струна до ansi ($'\t') и замена процесса (<(...)) избегать цикла с условием продолжения в проблеме подоболочки.

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

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done 3<file1 4<file2

Не протестированный очень. Мог бы повредиться на пустых строках.

Дескрипторы файлов номер 0, 1, и 2 уже используются для stdin, stdout, и stderr, соответственно. Дескрипторы файлов от 3 и (обычно) свободны. Руководство удара предупреждает от использования дескрипторов файлов, больше, чем 9, потому что они "используются внутренне".

Обратите внимание, что открытые дескрипторы файлов наследованы для окружения функций и внешних программ. Функции и программы, наследовавшие открытый дескриптор файла, могут читать из (и записать в), дескриптор файла. Необходимо заботиться для закрытия всех дескрипторов файлов, которые не требуются прежде, чем назвать функциональную или внешнюю программу.

Вот та же программа как выше с фактической работой (печать) разделена от метаработы (читающий линию за линией из двух файлов параллельно).

work() {
  printf 'f1: %s\n' "$1"
  printf 'f2: %s\n' "$2"
}

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  work "$f1" "$f2"
done 3<file1 4<file2

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

unknowncode() {
  printf 'f1: %s\n' "$1"
  printf 'f2: %s\n' "$2"
  read -r yoink <&3 && printf 'yoink: %s\n' "$yoink"
}

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  unknowncode "$f1" "$f2"
done 3<file1 4<file2

Вот вывод в качестве примера. Обратите внимание, что вторая строка из первого файла "украдена" от цикла.

f1: file1 line1
f2: file2 line1
yoink: file1 line2
f1: file1 line3
f2: file2 line2

Вот то, как необходимо закрыть дескрипторы файлов прежде, чем назвать внешний код (или любой код в этом отношении).

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  # this will close fd3 and fd4 before executing anycode
  anycode "$f1" "$f2" 3<&- 4<&-
  # note that fd3 and fd4 are still open in the loop
done 3<file1 4<file2
33
27.01.2020, 19:39

Откройте эти два файла на различных дескрипторах файлов. Перенаправьте вход read встроенный к дескриптору, который файл Вы хотите, подключен с. В bash/ksh/zsh можно записать read -u 3 вместо read <&3.

while IFS= read -r lineA && IFS= read -r lineB <&3; do
  echo "$lineA"; echo "$lineB"
done <fileA 3<fileB

Этот отрывок останавливается, когда самый короткий файл был обработан. Посмотрите, что Чтение двух файлов в цикл с условием продолжения IFS - Является там способом получить нулевой различный результат в этом случае? если Вы хотите продолжать обрабатывать до конца обоих файлов.

См. также при использовании дополнительного дескриптора файла? для получения дополнительной информации о дескрипторах файлов, и Почему, 'в то время как IFS = читала' используемый так часто вместо 'IFS =; в то время как считано..'? для объяснения IFS= read -r.

17
27.01.2020, 19:39
  • 1
    Спасибо @Gilles для дополнительных ссылок на дескриптор файла. –  jaypal singh 12.12.2011, 03:31
  • 2
    @Gilles, возможно, я неправильно понял Вас, но я не мог заставить цикл обработать самый длинный файл полностью (который всегда является $fileA в моем случае), таким образом, я превратил это в отдельный вопрос, будучи: существует ли способ записать цикл так, чтобы разность не замечала различия между вводом и выводом? unix.stackexchange.com/questions/26780 / … самое близкое, которое я мог получить, был разностью только нахождение одной строки различия. –  ixtmixilix 14.12.2011, 13:36

Я знаю, что Вы хотите сценарий оболочки, но Вы могли бы хотеть смотреть на paste команда.

3
27.01.2020, 19:39
  • 1
    Спасибо @lutzky. paste прохладно также. –  jaypal singh 19.12.2011, 22:37

С другой стороны, я предполагаю, что Вы могли хлебать файл в переменную типа массив, связывающую каждую строку файла в массив [line_of_file_index] использование команды mapfile удара. Однако я не уверен, только ли это для Bash3 выше или Bash4.

http://wiki.bash-hackers.org/commands/builtin/mapfile

0
27.01.2020, 19:39

Попробуйте выполнить команду ниже:

paste -d '\n' inp1.txt inp2.txt > outfile.txt
2
27.01.2020, 19:39

Теги

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