![Проверьте, содержит ли папка файлы с расширениями и запишите каталоги в категории](https://rvso.com/image/1684200/%D0%9F%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D1%8C%D1%82%D0%B5%2C%20%D1%81%D0%BE%D0%B4%D0%B5%D1%80%D0%B6%D0%B8%D1%82%20%D0%BB%D0%B8%20%D0%BF%D0%B0%D0%BF%D0%BA%D0%B0%20%D1%84%D0%B0%D0%B9%D0%BB%D1%8B%20%D1%81%20%D1%80%D0%B0%D1%81%D1%88%D0%B8%D1%80%D0%B5%D0%BD%D0%B8%D1%8F%D0%BC%D0%B8%20%D0%B8%20%D0%B7%D0%B0%D0%BF%D0%B8%D1%88%D0%B8%D1%82%D0%B5%20%D0%BA%D0%B0%D1%82%D0%B0%D0%BB%D0%BE%D0%B3%D0%B8%20%D0%B2%20%D0%BA%D0%B0%D1%82%D0%B5%D0%B3%D0%BE%D1%80%D0%B8%D0%B8.png)
У меня около 3k + папок, и они могут иметь два типа файлов, один файл spring и пару файлов fastq.gz. Я хочу просканировать папки и узнать, присутствуют ли оба или одно из расширений файла в каталоге -
- Содержат пару файлов fastq.gz и spring
- Один файл fastq.gz и файл spring
- Один пружинный файл
- Пара файлов fastq.gz
- Один файл 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 -f
isдопуть к тесту. Все еще [ -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-