Я пытаюсь проверить тип данного файла, и если это то, что я ожидаю. Он может иметь одно из трех расширений .fa, .fasta или .fasta.gz. Глядя на другие вопросы, я думаю, что это должно быть довольно тривиально, однако, когда я пробую предложения, они не работают для меня.
Это то, что я пробовал, все из которых не совпадают:
#!/bin/bash
test1 = "abcdef.fa"
test2 = "ghijkl.fasta"
test3 = "mnopqr.fasta.gz"
echo "test1: $test1"
echo "test2: $test2"
echo "test3: $test3"
# Attempt 1
if [[ $test1 =~ *.fa|*.fasta|*.fasta.gz ]] &> /dev/null; then printf "Attempt1: Match with $test1\n"; fi
if [[ $test2 =~ *.fa|*.fasta|*.fasta.gz ]] &> /dev/null; then printf "Attempt1: Match with $test2\n"; fi
if [[ $test3 =~ *.fa|*.fasta|*.fasta.gz ]] &> /dev/null; then printf "Attempt1: Match with $test3\n"; fi
# Attempt 2 - do I need to quote the string?
if [[ "$test1" =~ *.fa|*.fasta|*.fasta.gz ]] &> /dev/null; then printf "Attempt2: Match with $test1\n"; fi
if [[ "$test2" =~ *.fa|*.fasta|*.fasta.gz ]] &> /dev/null; then printf "Attempt2: Match with $test2\n"; fi
if [[ "$test3" =~ *.fa|*.fasta|*.fasta.gz ]] &> /dev/null; then printf "Attempt2: Match with $test3\n"; fi
# Attempt 3 - alternative regex
if [[ $test1 =~ .\*.(fa|fasta|fasta.gz) ]] &> /dev/null; then printf "Attempt3: Match with $test1\n"; fi
if [[ $test2 =~ .\*.(fa|fasta|fasta.gz) ]] &> /dev/null; then printf "Attempt3: Match with $test2\n"; fi
if [[ $test3 =~ .\*.(fa|fasta|fasta.gz) ]] &> /dev/null; then printf "Attempt3: Match with $test3\n"; fi
# Attempt 4 - again with the quoted string
if [[ "$test1" =~ .\*.(fa|fasta|fasta.gz) ]] &> /dev/null; then printf "Attempt4: Match with $test1\n"; fi
if [[ "$test2" =~ .\*.(fa|fasta|fasta.gz) ]] &> /dev/null; then printf "Attempt4: Match with $test2\n"; fi
if [[ "$test3" =~ .\*.(fa|fasta|fasta.gz) ]] &> /dev/null; then printf "Attempt4: Match with $test3\n"; fi
# Attempt 5 - put $ on end of regex
if [[ $test1 =~ .\*.(fa|fasta|fasta.gz)$ ]] &> /dev/null; then printf "Attempt5: Match with $test1\n"; fi
if [[ $test2 =~ .\*.(fa|fasta|fasta.gz)$ ]] &> /dev/null; then printf "Attempt5: Match with $test2\n"; fi
if [[ $test3 =~ .\*.(fa|fasta|fasta.gz)$ ]] &> /dev/null; then printf "Attempt5: Match with $test3\n"; fi
# Attempt 6 - again with the quoted string
if [[ "$test1" =~ .\*.(fa|fasta|fasta.gz)$ ]] &> /dev/null; then printf "Attempt6: Match with $test1\n"; fi
if [[ "$test2" =~ .\*.(fa|fasta|fasta.gz)$ ]] &> /dev/null; then printf "Attempt6: Match with $test2\n"; fi
if [[ "$test3" =~ .\*.(fa|fasta|fasta.gz)$ ]] &> /dev/null; then printf "Attempt6: Match with $test3\n"; fi
# Attempt 7 - use double ||
if [[ $test1 =~ .\*.(fa||fasta||fasta.gz) ]] &> /dev/null; then printf "Attempt7: Match with $test1\n"; fi
if [[ $test2 =~ .\*.(fa||fasta||fasta.gz) ]] &> /dev/null; then printf "Attempt7: Match with $test2\n"; fi
if [[ $test3 =~ .\*.(fa||fasta||fasta.gz) ]] &> /dev/null; then printf "Attempt7: Match with $test3\n"; fi
Я близок к этому:
# Attempt 8 - escape parentheses
if [[ $test1 =~ .\*.\(fa|fasta|fasta.gz\) ]] &> /dev/null; then printf "Attempt8: Match with $test1\n"; fi
if [[ $test2 =~ .\*.\(fa|fasta|fasta.gz\) ]] &> /dev/null; then printf "Attempt8: Match with $test2\n"; fi
if [[ $test3 =~ .\*.\(fa|fasta|fasta.gz\) ]] &> /dev/null; then printf "Attempt8: Match with $test3\n"; fi
Однако первый тест не работает, и вывод выглядит следующим образом:
test1: abcdef.fa
test2: ghijkl.fasta
test3: mnopqr.fasta.gz
Attempt8: Match with ghijkl.fasta
Attempt8: Match with mnopqr.fasta.gz
Что мне не хватает?





=~ должен принимать шаблоны регулярных выражений, а не шаблоны глобусов. Попробуйте \.(fa|fasta|fasta\.gz)$.
Также вы можете использовать расширенное сопоставление с образцом: [[ $test1 == *.@(fa|fasta|fasta.gz) ]]
@gildux Действительно заманчиво объединить все общие компоненты в шаблон, но на самом деле это не делает его лучше для чего-то такого простого, как этот.
Это зависит от того, как закодирован механизм регулярных выражений (и я не знаю для bash, поэтому мои последние слова) и как выполняется слияние. Я думаю о выступлениях… Но это не очевидная тема. :)
Гораздо проще определить регулярное выражение в переменной:
#!/usr/bin/env bash
test1 = "abcdef.fa"
test2 = "ghijkl.fasta"
test3 = "mnopqr.fasta.gz"
echo "test1: $test1"
echo "test2: $test2"
echo "test3: $test3"
pattern='\.(fa|fasta|fasta.gz)$'
# Attempt 1
if [[ $test1 =~ $pattern ]] &> /dev/null; then printf "Attempt1: Match with $test1\n"; fi
if [[ $test2 =~ $pattern ]] &> /dev/null; then printf "Attempt1: Match with $test2\n"; fi
if [[ $test3 =~ $pattern ]] &> /dev/null; then printf "Attempt1: Match with $test3\n"; fi
Вы можете попробовать оператор case, например:
case "$test1" in
*.fa|*.fasta|*.fasta.gz) printf 'Attempt1: Match with %s\n' "$test1";;
esac
case "$test2" in
*.fa|*.fasta|*.fasta.gz) printf 'Attempt1: Match with %s\n' "$test2";;
esac
case "$test3" in
*.fa|*.fasta|*.fasta.gz) printf 'Attempt1: Match with %s\n' "$test3";;
esac
Смотрите help case
Смотрите LESS='+/case word in' man bash
OP использует шаблон глобуса, поэтому подход с оператором case актуален. Проголосовать.
Вы можете использовать либо сопоставление с регулярным выражением, либо сопоставление с образцом с помощью [[ ... ]].
# regular expression
[[ $test1 =~ \.(fa|fasta|fasta.gz)$ ]]
# pattern match
[[ $test1 = *.@(fa|fasta|fasta.gz) ]]
Регулярные выражения не привязаны ни к одному из концов строки, поэтому вам нужно сопоставить $, чтобы расширения действительно находились в конце строки, а не только где-то в середине. (...) — это список альтернатив на выбор
Совпадения с образцом привязаны к обоим концам, поэтому вам нужен *, чтобы сопоставить всю строку до расширения. @(...) — это список альтернатив на выбор.
В обоих случаях заключать в кавычки левый операнд необязательно.
Вместо
\.(fa|fasta|fasta\.gz)$я бы предпочел\.fa(sta(\.gz)?)?$, если это возможно.