У меня есть строка в оболочке Linux. Эта строка содержит в себе символы подчеркивания.
Я хочу извлечь из строки подстроку.
Я хочу извлечь подстроку после третьего символа подчеркивания, отсчитываемого от конца строки.
file_name='email_Tracking_export_history_2018_08_15'
string_name = "${file_name#*_*_*_}"
file_name2='email_Tracking_export_2018_08_15'
string_name2 = "${file_name2#*_*_*_}"
echo "$string_name"
echo "$string_name2"
Результат
history_2018_08_15
2018_08_15
Как видите, string_name = "${file_name#*_*_*_}"
работает некорректно.
Желаемый результат:
2018_08_15
2018_08_15
Как добиться желаемого результата?
Используйте временную переменную:
file_name='email_Tracking_export_history_2018_08_15'
temp = "${file_name%_*_*_*}"
string_name = "${file_name/${temp}_}"
file_name2='email_Tracking_export_2018_08_15'
temp = "${file_name2%_*_*_*}"
string_name2 = "${file_name2/${temp}_}"
echo "$string_name"
echo "$string_name2"
Как насчет использования регулярного выражения в bash:
#!/bin/bash
# Extract substring from string after 3rd occurrence in reverse
function extract() {
if [[ "$1" =~ _([^_]+_[^_]+_[^_]+$) ]]; then
echo "${BASH_REMATCH[1]}"
fi
}
file_name='email_Tracking_export_history_2018_08_15'
string_name=$(extract $file_name)
file_name2='email_Tracking_export_2018_08_15'
string_name2=$(extract $file_name2)
echo "$string_name"
echo "$string_name2"
Вы можете сделать это за один шаг, но это немного запутано. После установки имени файла
file_name='email_Tracking_export_history_2018_08_15'
мы получаем подстроку, содержащую все Кроме, что мы хотим получить в итоге:
$ echo "${file_name%_*_*_*}"
email_Tracking_export_history
Это почти то, что нам нужно, только отсутствует подчеркивание, поэтому мы добавляем следующее:
$ echo "${file_name%_*_*_*}_"
email_Tracking_export_history_
Теперь мы знаем, что нам нужно удалить из начала строки и вставить это в расширение ${word#pattern}
:
$ echo "${file_name#"${file_name%_*_*_*}_"}"
2018_08_15
или присваиваем его переменной для дальнейшего использования:
string_name=${file_name#"${file_name%_*_*_*}_"}
└───┬───┘ │ └───┬───┘ └─┬──┘ │
outer word │ inner word └────────inner pattern
└───outer pattern────┘
Аналогично для второй струны.
% echo $file_name | rev | cut -f1-3 -d'_' | rev
2018_08_15
% echo $file_name2 | rev | cut -f1-3 -d'_' | rev
2018_08_15
rev
переворачивает строку, облегчая подсчет 3 случаев подчеркивания. Затем часть строки, которую вы хотите извлечь, переворачивается обратно.
Используя (большинство) sed и BRE:
sed 's/.*_\([^_]*\(_[^_]*\)\{2\}\)$/\1/' <<< "$file_name"
2018_08_15
Использование GNU sed и ERE:
sed -r 's/.*_([^_]*(_[^_]*){2})$/\1/' <<< "$file_name"
2018_08_15
expr
уже забанен до дьявола даже за сопоставление строк ?:
$ expr "$file_name" : '.*_\([^_]*_[^_]*_[^_]*\)'
2018_08_15
$ expr "$file_name2" : '.*_\([^_]*_[^_]*_[^_]*\)'
2018_08_15
От https://www.tldp.org/LDP/abs/html/string-manipulation.html:
expr "$string" : '.*\($substring\)'
Extracts $substring at end of $string, where $substring is a regular expression.