Есть ли способ указать несколько переменных (не только целые числа) в forциклах в bash? У меня может быть 2 файла, содержащие произвольный текст, с которым мне нужно было бы работать.
Что мне функционально нужно, так это:
for i in $(cat file1) and j in $(cat file2);do command $i $j;done
Во-первых, не читайте строки с помощью for , так как есть несколько неизбежных проблем с чтением строк с помощью разделения слов.
Предполагая, что файлы равной длины, или если вы хотите зацикливаться только до тех пор, пока не будет прочитано более короткое из двух файлов, возможно простое решение.
while read -r x && read -r y <&3;do...done<file1 3<file2
Составить более общее решение сложно из-за того, что readвозвращает false, и по нескольким другим причинам. В этом примере можно прочитать произвольное количество потоков и вернуться после самого короткого или самого длинного ввода.
#!/usr/bin/env bash# Open the given files and assign the resulting FDs to arrName.# openFDs arrname file1 [file2 ...]
openFDs(){local x y i arr=$1
[[-v $arr ]]||return1
shift
for x;do{ exec {y}<"$x";}2>/dev/null ||return1
printf -v "${arr}[i++]"%d "$y"done}# closeFDs FD1 [FD2 ...]
closeFDs(){local x
for x;do
exec {x}<&-done}# Read one line from each of the given FDs and assign the output to arrName.# If the first argument is -l, returns false only when all FDs reach EOF.# readN [ -l ] arrName FD1 [FD2 ...]
readN(){if[[ $1 ==-l ]];thenlocal longest
shift
elselocal longest=filocal i x y status arr=$1
[[-v $arr ]]||return1
shift
for x;doif IFS= read -ru "$x""${arr}[i]"||{ unset -v "${arr}[i]";[[ ${longest+_}]]&&return1;};then
status=0fi((i++))donereturn ${status:-1}}# readLines file1 [file2 ...]
readLines(){local-a fds lines
trap 'closeFDs "${fds[@]}"' RETURN
openFDs fds "$@"||return1while readN -l lines "${fds[@]}";do
printf '%-1s '"${lines[@]}"
echo
done}{
readLines /dev/fd/{3..6}||{ echo 'error occured'>&2; exit 1;}}<<<$'a\nb\nc\nd'3<&0<<<$'1\n2\n3\n4\n5'4<&0<<<$'x\ny\nz'5<&0<<<$'7\n8\n9\n10\n11\n12'6<&0# vim: set fenc=utf-8 ff=unix ts=4 sts=4 sw=4 ft=sh nowrap et:
Таким образом, в зависимости от того, readNполучает ли -l, либо
a 1 x 7
b 2 y 8
c 3 z 9
d 41051112
или
a 1 x 7
b 2 y 8
c 3 z 9
Необходимость читать несколько потоков в цикле без сохранения всего в несколько массивов не так уж часто. Если вы просто хотите читать массивы, вы должны посмотреть mapfile.
||не работает для меня Он обрабатывает file1 затем file2 , но это сохранить файлы синхронизируются с &&, который выходит из то время как цикл по первому EOF . - GNU bash 4.1.5
Peter.O
У меня не было свободного времени для тестирования - да, вы, вероятно, захотите оба элемента на одну итерацию. Оператор ||«list» имеет короткое замыкание, как и в большинстве языков. Конечно, на это уже тысячи раз ответили ...
ormaaj
Дело не в том, как часто что-то упоминалось ранее. Скорее всего, код, который вы сейчас показываете в своем ответе , не работает . Исходя из вашего « вероятно, хотите оба элемента ..», похоже, что вы все еще не проверяли это.
Peter.O
@ Peter.O я в курсе. Это было исправлено.
ormaaj
2
Есть ли сделано; готово - вам нужны два форса и два квеста:
for i in $(< file1);dofor j in $(< file2);do echo $i $j;done;done
Файл2, конечно, обрабатывается для каждого слова в файле1 один раз.
Использование <вместо cat в большинстве случаев должно быть незначительным приростом производительности. Подпроцесс не задействован. (Не уверен насчет последнего предложения).
несжатый:
for i in $(< file1)dofor j in $(< file2)do
echo $i $j
donedone
Если вам не нравится читать слова, кроме строк и сохранять пробелы, используйте while и прочитайте:
while read line;dowhile read second;do echo "${line}${second}";done<file2 ;done<file1
Если вы хотите добавить 2 файла, а не вкладывать их:
Вы говорите, что подпроцесс не задействован. Не является ли () подоболочкой? Я не хочу быть подвесным, но я не уверен, что происходит сейчас. Например, я знаю, что когда у меня есть скрипт, и я не хочу, чтобы он, например, добавлял в текущую оболочку cd, я делаю это внутри (). Также работает (сон 4) и, например, после ps показывает, что процесс все еще работает. Можете ли вы уточнить, пожалуйста.
Silverrocker
Ну, извини, я очень много играю здесь без оснований. Я думал, что слышал так, но, возможно, это только по <сравнению с cat. И я не уверен, как это проверить, и когда это станет семантически важным. Если каналы вызваны, переменные в подпроцессах не попадают в основной процесс, но у нас здесь нет переменных. Я вычеркиваю критическое предложение, пока кто-нибудь не сможет его прояснить.
пользователь неизвестен
0
whileимеет интересный синтаксис. Вы можете поместить несколько команд перед do ... whileциклом, и рассматриваемый случай может потребовать манипулирования этой функцией, в зависимости от ваших конкретных требований: читаете ли вы до конца самого длинного файла или только до конца самого короткого.
Например, read || readпросто не работает (в соответствии с требованиями вопроса), поскольку при чтении первого файла trueчтение второго файла пропускается до тех пор, пока первый файл не будет прочитан от начала до конца ... Тогда, потому что статус все еще true, цикл while продолжается и читает второй файл от начала до конца.
read && readбудет читать файлы одновременно (синхронно), если вы хотите прочитать только самый короткий файл. Однако, если вы хотите прочитать оба файла eof, вам нужно работать с while'sтребованиями синтаксиса, т.е. по команде непосредственно передdo while тем цикл производства ненулевого кода возврата вырваться из цикла While.
||
не работает для меня Он обрабатывает file1 затем file2 , но это сохранить файлы синхронизируются с&&
, который выходит из то время как цикл по первому EOF . - GNU bash 4.1.5||
«list» имеет короткое замыкание, как и в большинстве языков. Конечно, на это уже тысячи раз ответили ...Есть ли сделано; готово - вам нужны два форса и два квеста:
Файл2, конечно, обрабатывается для каждого слова в файле1 один раз.
Использование <вместо cat в большинстве случаев должно быть незначительным приростом производительности.
Подпроцесс не задействован.(Не уверен насчет последнего предложения).несжатый:
Если вам не нравится читать слова, кроме строк и сохранять пробелы, используйте while и прочитайте:
Если вы хотите добавить 2 файла, а не вкладывать их:
Если вы хотите сжать 2 файла, используйте paste:
источник
<
сравнению сcat
. И я не уверен, как это проверить, и когда это станет семантически важным. Если каналы вызваны, переменные в подпроцессах не попадают в основной процесс, но у нас здесь нет переменных. Я вычеркиваю критическое предложение, пока кто-нибудь не сможет его прояснить.while
имеет интересный синтаксис. Вы можете поместить несколько команд передdo ... while
циклом, и рассматриваемый случай может потребовать манипулирования этой функцией, в зависимости от ваших конкретных требований: читаете ли вы до конца самого длинного файла или только до конца самого короткого.Например,
read || read
просто не работает (в соответствии с требованиями вопроса), поскольку при чтении первого файлаtrue
чтение второго файла пропускается до тех пор, пока первый файл не будет прочитан от начала до конца ... Тогда, потому что статус все ещеtrue
, цикл while продолжается и читает второй файл от начала до конца.read && read
будет читать файлы одновременно (синхронно), если вы хотите прочитать только самый короткий файл. Однако, если вы хотите прочитать оба файлаeof
, вам нужно работать сwhile's
требованиями синтаксиса, т.е. по команде непосредственно передdo while
тем цикл производства ненулевого кода возврата вырваться из цикла While.Вот пример того, как читать оба файла на eof
(вы можете захотеть проверить eof3 и eof4 перед чтением, но общая идея есть, особенно в конечном состоянии true / false.
источник