2010-09-20 4 views
0

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

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

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) 

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

+0

@Andrew - так что если есть точное совпадение, вы хотите _just_, но если нет точного соответствия, будет выполняться «частичное» совпадение? –

+0

@martin clayton Да, требуется частичное совпадение, если точное совпадение не найдено. – Gargauth

+0

Ладно, кажется, что я не был лучшим вариантом. Позвольте мне попробовать еще раз - строка 'Foo Bar 09.20.2010' должна соответствовать файлу' Foo Bar.txt'. А файл 'Foo Bar Foo 09.20.2010' должен соответствовать файлу' Foo Bar Foo.txt'. Надеюсь, теперь это имеет смысл ... – Gargauth

ответ

1

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

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

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

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

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

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

например.как

echo "$string"* 

и

ls "$string"* 

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

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

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

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

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

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

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

+0

На самом деле я не против использования perl/python/php или любого другого языка, который выполнит эту работу. Я просто нахожу bash немного проще в использовании, хотя я добавляю много лишних команд, как вы сказали :) – Gargauth

Смежные вопросы