Проверьте, содержит ли папка файлы с расширениями и запишите каталоги в категории

Проверьте, содержит ли папка файлы с расширениями и запишите каталоги в категории

У меня около 3k + папок, и они могут иметь два типа файлов, один файл spring и пару файлов fastq.gz. Я хочу просканировать папки и узнать, присутствуют ли оба или одно из расширений файла в каталоге -

  1. Содержат пару файлов fastq.gz и spring
  2. Один файл fastq.gz и файл spring
  3. Один пружинный файл
  4. Пара файлов fastq.gz
  5. Один файл fastq.gz

Я использовал [ /path/to/dir/*fastq.gz ], но получаю сообщение unary operator expectedоб ошибке, и использование, [[ ]]похоже, не выполняет корректную проверку.

Фактический сценарий, который я использовал, это -

check_dir () {
in="$1"
echo "$in Checking for spring"
[ "$in"/*spring -f ] && echo "$in"
}
export -f check_dir

Я использую bash, любая помощь с логикой будет оценена по достоинству.

решение1

unary operator expectedпотому что [и *(в вашем *fastq.gz) работают независимо.

[не является синтаксисом оболочки. [является обычной командой (встроенной в Bash, но все же командой) и ]является ее последнейаргумент, обязательный. Все, что между ними, тоже аргумент.

Оболочка расширяется /path/to/dir/*fastq.gzдо одного или нескольких слов, прежде чем вызвать [. [увидит эти слова и обязательные ]в качестве аргументов. В зависимости от количества аргументов и того, что они собой представляют, [ожидает ноль или более аргументов, которые будут операторами (например -f).

Ваш [ /path/to/dir/*fastq.gz ]будет допустимым, если /path/to/dir/*fastq.gzразвернется до одного аргумента (обратите внимание, что «будет допустимым» не эквивалентно «будет делать то, что вы хотите»). Это включает в себя случаи, когда *ничего не соответствует; традиционно (и по умолчанию в Bash) если нет соответствия, то /path/to/dir/*fastq.gzбудет обработано как есть. Может случиться, /path/to/dir/*fastq.gzчто развернется до нескольких слов, ни одно из них не будет выглядеть так, как оператор [понимает. Ошибка, которую вы получили, скорее всего, возникла из-за случая, когда шаблон развернулся до двух слов.

Позже вы использовали [ "$in"/*spring -f ]. Это еще хуже, потому что вы, вероятно, хотели что-то вроде [ -f some/path ]where -fisдопуть к тесту. Все еще [ -f "$in"/*spring ]не является надежным решением, потому что"$in"/*spring в общемможет расшириться до нескольких аргументов и [не будет их терпеть. Вы написали, что в каталоге может быть максимум один *springфайл, поэтомув твоем случаеТакой код может работать, но это все равно плохой код.

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

Вы хотите узнать, сколько файлов соответствует шаблону /path/to/dir/*fastq.gz. Правильный способ сделать это — присвоить результат расширения массиву. Переносимо существует только один массив: массив аргументов скрипта оболочки (или функции оболочки); и вам нужен дополнительный код для обнаружения случая нулевого соответствия (который все равно генерирует одно слово: нерасширенную строку шаблона). Ваш вопрос помечен, поэтому я буду использовать именованный массив и несколько других непереносимых функций:

# non-portable code, works in Bash
check_dir () (
   dir="${1-.}"
   dir="${dir%/}/"
   [ -d "$dir" ] || { echo "Not a directory." >&2; return 1; }
   shopt -s nullglob
   files=( "$dir"/*fastq.gz )
   nf="${#files[@]}"
   files=( "$dir"/*spring )
   ns="${#files[@]}"
   printf '%s\t%s\t%s\n' "$nf" "$ns" "$dir"
)

Использование: check_dir path/to/dirили check_dir(путь по умолчанию — .). Функция выведет количество *fastq.gzфайлов, вкладку, количество *springфайлов, вкладку, наконец, проверенный путь (выводится с конечным /).

Now you can analyze a directory tree (the below function requires the above function to be defined):

# non-portable code, works in Bash
check_dirs () (
   dir="${1-.}"
   dir="${dir%/}/"
   [ -d "$dir" ] || { echo "Not a directory." >&2; return 1; }
   shopt -s nullglob globstar
   for d in "$dir"**/; do
      check_dir "$d"
   done
)

Использование: check_dirs path/to/dirили check_dirs(путь по умолчанию — .).

Примечания:

  • Для большого дерева каталогов check_dirsможет показаться, что оно изначально останавливается. Это потому, что его for d in "$dir"**/нужно полностью развернуть, прежде чем check_dirон когда-либо будет вызван и что-либо напечатает.

  • Функции намеренно определены как подоболочки ( check_dir () (в отличие от check_dir () {), поэтому параметры оболочки ( shopt) и все переменные являются локальными.

  • Если вы хотите check_dirподсчитать скрытые файлы, вам нужна dotglobэта функция (т.е. shopt -s nullglob dotglob).

  • Если вы хотите check_dirsспуститься в скрытые каталоги, вам нужна dotglobэта функция (т.е. shopt -s nullglob globstar dotglob).

  • Если имена ваших каталогов не содержат символы новой строки, вывод от check_dirили check_dirsлегко анализируется стандартными инструментами. Полезные команды: sort -n, grep $'^2\t1\t', cut -f 3-.

    Например, чтобы найти каталоги, содержащие ./ровно один *fastq.gzфайл и ровно ноль *springфайлов:

    check_dirs | grep $'^1\t0\t' | cut -f 3-
    

Связанный контент