2010-01-07 2 views
1
 
I have lots of strings in a text file, like this: 

"/home/mossen/Desktop/jeff's project/Results/FCCY.png" 
"/tmp/accept/FLWS14UU.png" 
"/home/tten/Desktop/.wordi/STSMLC.png" 

Я хочу получить только имена файлов из строки, когда я читаю текстовый файл по строкам, используя сценарий оболочки bash. Имя файла всегда будет заканчиваться на .png и всегда будет иметь перед ним «/». Я могу получить каждую строку в var, но каков наилучший способ извлечь имена файлов (FCCY.png, FLWS14UU.png и т. Д.) В vars? Я не могу рассчитывать на то, что у пользователя есть Perl, Python и т. Д., Только стандартные утилиты Unix, такие как awk и sed.Как извлечь подстроку из текстового файла в bash?

 
Thanks, 
mossen 

ответ

3

Вы хотите basename:

$ basename /tmp/accept/FLWS14UU.png 
FLWS14UU.png 
+0

Wow, thats действительно простой. Спасибо за быстрый ответ! – Mossen

0
$ var="/home/mossen/Desktop/jeff's project/Results/FCCY.png" 
$ file="${var##*/}" 
1

работает на базовое один файл/строку в то время. Если у вас много строк, вы будете многократно повторять файл и вызывать внешнюю команду.

Использование AWK

$ awk -F'[/"]' '{print $(NF-1)}' file 
FCCY.png 
FLWS14UU.png 
STSMLC.png 

или использовать оболочку

while read -r line 
do 
    line=${line##*/} 
    echo "${line%\"}" 
done <"file" 
0

Использование итеративно имеет базовое имя огромный удар по производительности. Это мало и незаметно, когда вы делаете это в файле или два, но добавляет более сотни из них. Позвольте мне сделать некоторые тесты времени, чтобы вы могли проиллюстрировать, почему использование basneame (или любая служебная выноска системы) плохо, когда внутренняя функция может выполнять эту работу - Dennis и ghostdog74 дали вам более опытные ответы BASH.

ввод образца files.txt (список моих фотографий с полным путем): записей

external.sh

while read -r line 
do 
    line=`basename "${line}"` 
    echo "${line%\"}" 
done < "files.txt" 

internal.sh

while read -r line 
do 
    line=${line##*/} 
    echo "${line%\"}" 
done < "files.txt" 

Временные результаты, перенаправление вывода на/dev/null до избавиться от любого видео лаг:

$ time sh external.sh 1>/dev/null 

real 0m4.135s 
user 0m1.142s 
sys 0m2.308s 

$ time sh internal.sh 1>/dev/null 

real 0m0.413s 
user 0m0.357s 
sys 0m0.021s 

Выход обоих одинакова:

$ sh external.sh | sort > result1.txt 
$ sh internal.sh | sort > result2.txt 
$ diff -uN result1.txt result2.txt 

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