Извлечение числа из имени файла

Удалите VirtualBox-5.0 и установите VirtualBox-5.1

2
26.04.2017, 00:36
2 ответа

cut - неподходящий инструмент для этого. Для манипулирования короткими строками, такими как имена файлов, используйте средства манипулирования строками оболочки, когда это возможно. Все оболочки типа sh¹ (sh, dash, bash, ksh, zsh, ...) имеют некоторые базовые средства работы со строками как часть подстановки переменных. Смотрите, например, руководство по dash в разделе "Расширение параметров". Вы можете удалить самый короткий/самый длинный префикс/суффикс, который соответствует шаблону.

Вам нужна последняя последовательность цифр в имени файла, поэтому:

  1. Определите нечисловой суффикс, вычеркнув все до последней цифры.
  2. Удалите этот суффикс.
  3. Вычеркните все до последней нецифровой цифры.
filename=1.raw_bank_details_211.trg
suffix="${filename##*[0-9]}"
number="${filename%"$suffix"}"
number="${number##*[!-0-9]}"

¹ За исключением некоторых оболочек Bourne до POSIX, но они вас не интересуют.

1
27.01.2020, 21:59

Вам лучше использовать стандартный инструмент обработки текста вместо наивного инструмента типа cut.

Вот несколько способов:


С помощью awk получить _ или . разделенное второе последнее поле:

awk -F '[_.]' '{print $(NF-1)}' file.txt

grep с PCRE (-P):

grep -Po '\d+(?=[^_]*$)' file.txt
  • -o получает только совпадающую часть

  • \d+ совпадает одна или несколько цифр

  • Положительный заголовок нулевой ширины, (? =[^_]*$), гарантирует, что ни один _ не следует до конца строки


С sed:

sed -E 's/.*_([[:digit:]]+).*/\1/' file.txt
  • . *_ соответствует всему до последнего _

  • ([[:цифра:]]+) соответствует нужным цифрам и помещается в захваченную группу

  • . * соответствует остальным

  • При замене используется только захваченная группа, \1


С perl, логика та же, что и с sed:

perl -pe 's/.*_(\d+).*/$1/' file.txt 

Если вы должны использовать cut, сделайте это в два шага, сначала получите _ разделенное 4-е поле, а затем получите разделенное 1-е поле:

cut -d_ -f4 file.txt | cut -d. -f1

Это не рекомендуется, так как требует жесткого кодирования номеров полей.


Если бы это была строка, я бы сделал это с помощью расширения параметров оболочки:

% str='1.raw_bank_details_211.trg'

% str=${str##*_} 

% echo "${str%%.*}"
211

Вы можете использовать конструкцию while и брать каждую строку в переменную и делать это, но это будет медленно для большого файла. Также в качестве альтернативы можно использовать _. в качестве IFS и получить вместо этого жестко закодированное поле (например, cut), если хотите.


Пример:

% cat file.txt                          
1.raw_bank_details_211.trg
2.raw_bank_details_222.trg

% awk -F '[_.]' '{print $(NF-1)}' file.txt
211
222

% grep -Po '\d+(?=[^_]*$)' file.txt         
211
222

% sed -E 's/.*_([[:digit:]]+).*/\1/' file.txt
211
222

% perl -pe 's/.*_(\d+).*/$1/' file.txt 
211
222

% cut -d_ -f4 file.txt | cut -d. -f1
211
222
4
27.01.2020, 21:59

Теги

Похожие вопросы