Bash: Итерация 2 списков с использованием одного цикла For In

Разработчики сочли это непонятным и изменили его более четырех лет назад:

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

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

Но документация для - relative-base и - relative-to , похоже, не была переформулирована, чтобы прояснить , что если - -relative-to не был указан, тогда по умолчанию используется значение, указанное для - relative-base .

2
12.02.2016, 18:41
4 ответа

Цикл while с подходящим вводом может выполнить эту работу, если в именах файлов нет символов новой строки.

paste -d/ <(ls /var) <(ls /usr) |
  while IFS=/ read -r e u; do
    printf '%s\n' "$e $u"
  done
3
27.01.2020, 21:56

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

#!/bin/bash
cd /
for file1 in $(ls /usr/ ; echo "::::::NEXT:::::::" ; ls /sys/)
do
    echo $file1
done
0
27.01.2020, 21:56

Обычно вы не хотите анализировать выводls.

Здесь сzsh(вы уже используете синтаксис zsh, а не bash, так как вы не заключаете свои переменные в кавычки и используете подстановку команд без отключения подстановки ), вы могли бы сделать:

dir1_file_names=(dir1/*(N:t))
dir2_file_names=(dir2/*(N:t))
for f1 f2 (${dir1_file_names:^dir2_file_names})
  printf '%s\n' "f1: $f1, f2: $f2"

zshможет зацикливаться с несколькими переменными. ${a:^b}— это оператор сжатия массива . Если в одном из массивов меньше элементов, чем в другом, это будет так, как если бы они были усечены до длины наименьшего.

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

file_names_in_both_dir1_and_dir2=(${dir1_file_names:*dir2_file_names})
file_names_only_in_dir1=(${dir1_file_name:|dir2_file_names})
file_names_only_in_dir2=(${dir2_file_name:|dir1_file_names})
2
27.01.2020, 21:56
shopt -s nullglob

dir1names=( Dir1/* )
dir2names=( Dir2/* )

while [ "${#dir1names[@]}" -gt 0 ] &&
      [ "${#dir2names[@]}" -gt 0 ]
do

    printf '%s\n' "${dir1names[0]##*/}"
    printf '%s\n' "${dir2names[0]##*/}"

    dir1names=( "${dir1names[@]:1}" )
    dir2names=( "${dir2names[@]:1}" )
done

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

Параметр оболочки nullglobзаставляет не совпадающие -подстановочные шаблоны расширяться до нуля, а не оставаться нерасширенными.

Тестирование:

$ tree
.
|-- Dir1
|   |-- file-1
|   |-- file-2
|   |-- file-3
|   `-- file-4
|-- Dir2
|   |-- otherfile-1
|   |-- otherfile-2
|   |-- otherfile-3
|   |-- otherfile-4
|   |-- otherfile-5
|   `-- otherfile-6
`-- script.sh

2 directories, 11 files
$ bash script.sh
file-1
otherfile-1
file-2
otherfile-2
file-3
otherfile-3
file-4
otherfile-4

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

Предположим, что файлы называются something_R1_moreи something_R2_more, где somethingи moreидентифицируют конкретнуюR1-R2пару файлов.

for r1 in dir1/*_R1_*; do
    r2=${r1##*/}              # dir1/something_R1_more --> something_R1_more
    r2=dir2/${r2/_R1_/_R2_}   # something_R1_more      --> dir2/something_R2_more

    if [ ! -f "$r2" ]; then
        printf '%s not found\n' "$r2" >&2
        exit 1
    fi

    # process "$r1" and "$r2" here
done
2
27.01.2020, 21:56

Теги

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