Bash find: список всех файлов с префиксами из цикла for

Вот небольшая [но полная] часть моего сценария bash, которая находит и выводит все файлы в mydir, если у них есть префикс из хранимого массива. Странная вещь, которую я замечаю, заключается в том, что этот скрипт отлично работает, если я вытащил из [сценария] -maxdepth 1 -name ", иначе он даст мне файлы с префиксом первого элемента массива.

Было бы очень полезно, если бы кто-то объяснил это мне. Извините заранее, если есть что-то явно глупое, что я делаю. Я относительно новичок в написании сценариев.

#!/bin/sh
DIS_ARRAY=(A B C D)
echo "Array is : "
echo ${DIS_ARRAY[*]}
for dis in $DIS_ARRAY
do
    IN_FILES='find /mydir  -maxdepth 1 -name "$dis*.xml"'
    for file in $IN_FILES
    do
    echo $file
    done
done

Вывод:

/mydir/Abc.xml
/mydir/Ab.xml
/mydir/Ac.xml

Ожидаемый результат:

/mydir/Abc.xml
/mydir/Ab.xml
/mydir/Ac.xml
/mydir/Bc.xml
/mydir/Cb.xml
/mydir/Dc.xml
+2
12 мар. '14 в 22:50
источник поделиться
2 ответа

Петля сломана в любом случае. Причина почему

IN_FILES='find mydir  -maxdepth 1 -name "$dis*.xml"'

работ, тогда как

IN_FILES='find mydir "$dis*.xml"'

это не так, потому что в первом вы указали -name. Во втором, find список всех файлов в mydir. Если вы измените второй на

IN_FILES='find mydir -name "$dis*.xml"'

вы увидите, что цикл не работает.

Как упоминалось в комментариях, синтаксис, который вы используете в настоящее время в $DIS_ARRAY, даст вам только первый элемент массива.

Попробуйте изменить свой цикл:

for dis in "${DIS_ARRAY[@]}"

В этом случае окружающие двойные кавычки не нужны, поэтому вы можете сделать:

for dis in ${DIS_ARRAY[@]}

Кавычки требуются, если в вашем массиве содержались пробелы, например, если вы хотите перебрать массив arr=( "aa" "bb" ).

Вот тест, показывающий, что происходит:

#!/bin/sh

arr=("a a" "b b")

echo using '$arr'
for i in $arr; do echo $i; done
echo using '${arr[@]}'
for i in ${arr[@]}; do echo $i; done
echo using '"${arr[@]}"'
for i in "${arr[@]}"; do echo $i; done

вывод:

using $arr
a
a
using ${arr[@]}
a
a
b
b
using "${arr[@]}"
a a
b b

См. Этот связанный вопрос для получения дополнительной информации.

+2
12 мар. '14 в 22:57
источник

Ответ @TomFenech решает вашу проблему, но позвольте мне предложить другие улучшения:

#!/usr/bin/env bash

DIS_ARRAY=(A B C D)
echo "Array is : "
echo ${DIS_ARRAY[*]}
for dis in "${DIS_ARRAY[@]}"
do
    for file in "/mydir/$dis"*.xml
    do
        if [ -f "$file" ]; then
            echo "$file"
        fi
    done
done
  • Ваши ссылки притон линии sh, но ваш вопрос помечен bash - если вам не требуется соответствие стандарта POSIX, использовать bash притон линию, чтобы воспользоваться всем, что bash может предложить
  • Чтобы сопоставлять файлы, расположенные непосредственно в заданном каталоге (т.е. Если вам не нужно перемещаться по целому поддереву), используйте glob (шаблон имени файла) и полагайтесь на расширение пути, как в моем коде выше, - нет необходимости в find и подстановке команд,
  • Обратите внимание, что символ подстановки. * UNKoted для обеспечения расширения пути.
  • Предостережение: если совпадающие файлы не найдены, glob остается нетронутым (если nullglob оболочки nullglob выключена, по умолчанию она), поэтому цикл вводится один раз с недопустимым именем файла (нерасширенный глобус) - следовательно, [ -f "$file" ] условно, чтобы убедиться, что найдено фактическое совпадение (в качестве альтернативы: использование базизмов, вы можете использовать [[ -f $file ]] вместо).
+1
12 мар. '14 в 23:18
источник

Посмотрите другие вопросы по метке или Задайте вопрос