Приоритет сравнения строк в Bash - PullRequest
0 голосов
/ 21 сентября 2010

В следующем примере будут сравниваться все файлы в каталоге с входной строкой ($ string) и возвращаться совпадающее имя файла. Это не очень элегантный и эффективный способ сделать это. Из соображений скорости я изменил условие for, чтобы оно сравнивалось только с файлами, которые начинаются с первого слова строки $.

Проблема с этим скриптом следующая - у меня в каталоге два файла:

Foo Bar.txt
Foo Bar Foo.txt

и я сравниваю их со строкой "Foo Bar 09.20.2010". Это вернет оба файла в этом каталоге, так как оба файла совпадают. Но мне нужно вернуть только тот файл, который наиболее точно соответствует строке - в нашем примере это должно быть Foo Bar.txt.

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

#!/bin/bash
string="Foo Bar 09.20.2010"

for file in /path/to/directory/$(echo "$string" | awk '{print $1}')*; do

    filename="${file##*/}"
    filename="${filename%.*}"


    if [[ $(echo "$string" | grep -i "^$filename") ]]; then
        result="$file"
        echo $result    
    fi

done

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

2 Файлы в каталоге (удалены расширения для соответствия):

Foo Bar.txt
Foo Bar Foo.txt

Для сравнения с 2 строками:

Foo Bar Random Additional Text
Foo Bar Foo Random Additional Text

Результаты:

compare "Foo Bar"(.txt) against Foo Bar Random Additional Text -> Match (Correct)
compare "Foo Bar"(.txt) against Foo Bar Foo Random Additional Text -> Match (Incorrect)

compare "Foo Bar Foo"(.txt) against Foo Bar Random Additional Text -> NOT Match (Correct)
compare "Foo Bar Foo"(.txt) against Foo Bar Foo Random Additional Text -> Match (Correct)

Спасибо всем за ваши ответы.

Ответы [ 2 ]

1 голос
/ 21 сентября 2010

Поправьте меня, если я ошибаюсь, но похоже, что ваш сценарий эквивалентен:

ls /path/to/directory/"$string"*

Если вы хотите использовать только одно имя файла, вы можете использовать head. Поскольку ls перечисляет файлы в алфавитном порядке, вы получите первый в алфавитном порядке.

(Обратите внимание, что когда вывод ls передается в другую программу, он печатает одно имя файла на строку, что облегчает его обработку, чем при обычном выводе на основе столбцов.)

ls /path/to/directory/"$string"* | head -1

Для самого короткого матча попробуйте что-то вроде следующего, в котором используется неуклюжая комбинация awk, sort -n и cut, чтобы упорядочить строки от самой короткой до самой длинной, а затем вывести первую один.

ls /path/to/directory/"$string"* |
    awk '{print length($0) "\t" $0}' | sort -n | head -1 | cut -f 2-
0 голосов
/ 21 сентября 2010

Многие ваши звонки echo и awk излишни.Чтобы получить все файлы, которые начинаются с вашего соответствия, вы можете просто оценить "$ string" *.

например, оба

echo "$string"*

и

ls "$string"*

Создадут ваши списки.(В трубе echo будет разделять их пробелами, а ls будет разделять их новыми строками).

Следующим шагом является осознание того, что, учитывая то, что вы определили, ваше дополнительное ограничение "«Наиболее точное совпадение» эквивалентно имени файла с самым коротким соответствием.

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

for fn in "/path/to/$string"*; do
  echo $(echo $fn | wc -c) "$fn"
done | sort -n | head -1 | cut -f2- -d' '

Цикл for проходит по расширенным именам файлов.Эхо добавляет длину имен к именам.Затем мы перенаправляем весь вывод этого в sort -n и head -1, чтобы получить самое короткое имя, а cut -f2- -d' ' удаляет его длину (беря второе поле с пробелом в качестве разделителя полей).

Ключ к программированию оболочки - это знание ваших строительных блоков и того, как их комбинировать.С умными комбинациями вида, головы, хвоста и кроя вы можете сделать довольно сложную обработку.Добавьте сюда sed и uniq, и вы уже сможете делать довольно впечатляющие вещи.

При этом я обычно использую оболочку только для таких вещей, как эта "на лету" - для всего, что я могу захотеть использовать повторно, и это вообще сложно, я был бы гораздо болеевероятно, использовать Perl.

...