Извлечь подстроку из строки после третьего последнего вхождения подчеркивания - PullRequest
0 голосов
/ 10 сентября 2018

У меня есть строка в оболочке 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

Как мне достичь желаемого результата?

Ответы [ 6 ]

0 голосов
/ 10 сентября 2018

Разве 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.
0 голосов
/ 10 сентября 2018

Используя (большинство) sed и BRE:

sed 's/.*_\([^_]*\(_[^_]*\)\{2\}\)$/\1/' <<< "$file_name"
2018_08_15

Использование GNU sed и ERE:

sed -r 's/.*_([^_]*(_[^_]*){2})$/\1/' <<< "$file_name"
2018_08_15
0 голосов
/ 10 сентября 2018
% 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 появлений подчеркивания. Часть строки, которую вы хотите извлечь, затем возвращается обратно.

0 голосов
/ 10 сентября 2018

Вы можете сделать это за один шаг, но это немного запутанно. После установки имени файла

file_name='email_Tracking_export_history_2018_08_15'

мы получаем подстроку, которая содержит все кроме того, что мы хотим получить в конце:

$ echo "${file_name%_*_*_*}"
email_Tracking_export_history

Это почти то, что мы хотим, просто отсутствует подчеркивание, поэтому мы добавим следующее:

$ echo "${file_name%_*_*_*}_"
email_Tracking_export_history_

Теперь мы знаем, что мы должны удалить из начала строки и вставить это в расширение ${<em>word</em>#<em>pattern</em>}:

$ echo "${file_name#"${file_name%_*_*_*}_"}"
2018_08_15

или мы присваиваем ее переменной для дальнейшего использования:

string_name=${file_name#"${file_name%_*_*_*}_"}
              └───┬───┘ │  └───┬───┘ └─┬──┘  │
             outer word │  inner word  └────────inner pattern
                        └───outer pattern────┘

И аналогично для второй строки.

0 голосов
/ 10 сентября 2018

Как насчет использования регулярных выражений в 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"
0 голосов
/ 10 сентября 2018

Использовать временную переменную:

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"
...