Извлеките часть строки, используя bash/cut/split

У меня есть такая строка:

/var/cpanel/users/joebloggs:DNS9=domain.com

Мне нужно извлечь имя пользователя (joebloggs) из этой строки и сохранить его в переменной.

Формат строки всегда будет то же самое, за исключением joebloggs и domain.com поэтому я имею в виду, что строка может быть разделена в два раза, используя cut?

Первое разделение будет разделено на : и мы сохраним первую часть в переменной для передачи второй функции разделения.

Второе разделение разделит на / и сохранит последнее слово (joebloggs) в переменной

Я знаю, как сделать это в php, используя массивы и разбиения, но я немного потерян в bash.

Ответ 1

Чтобы извлечь joebloggs из этой строки в bash, используя расширение параметров без каких-либо дополнительных процессов...

MYVAR="/var/cpanel/users/joebloggs:DNS9=domain.com" 

NAME=${MYVAR%:*}  # retain the part before the colon
NAME=${NAME##*/}  # retain the part after the last slash
echo $NAME

Не зависит от joebloggs находится ли joebloggs на определенной глубине пути.


Резюме

Обзор нескольких режимов расширения параметров, для справки...

${MYVAR#pattern}     # delete shortest match of pattern from the beginning
${MYVAR##pattern}    # delete longest match of pattern from the beginning
${MYVAR%pattern}     # delete shortest match of pattern from the end
${MYVAR%%pattern}    # delete longest match of pattern from the end

Таким образом, # означает совпадение с начала (подумайте о строке комментария), а % означает с конца. Один экземпляр означает самый короткий, а два - самый длинный.

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

${MYVAR:3}   # Remove the first three chars (leaving 4..end)
${MYVAR::3}  # Return the first three characters
${MYVAR:3:5} # The next five characters after removing the first 3 (chars 4-9)

Вы также можете заменить определенные строки или шаблоны, используя:

${MYVAR/search/replace}

pattern имеет тот же формат, что и сопоставление имени файла, поэтому * (любые символы) являются общими, часто за ними следует определенный символ, такой как / или .

Примеры:

Учитывая переменную, как

MYVAR="users/joebloggs/domain.com" 

Удалите путь, оставляя имя файла (все символы до косой черты):

echo ${MYVAR##*/}
domain.com

Удалите имя файла, оставив путь (удалите самое короткое совпадение после последнего /):

echo ${MYVAR%/*}
users/joebloggs

Получить только расширение файла (удалить все до последнего периода):

echo ${MYVAR##*.}
com

ПРИМЕЧАНИЕ. Чтобы выполнить две операции, вы не можете объединить их, но должны быть присвоены промежуточной переменной. Итак, чтобы получить имя файла без пути или расширения:

NAME=${MYVAR##*/}      # remove part before last slash
echo ${NAME%.*}        # from the new var remove the part after the last period
domain

Ответ 2

Определите такую ​​функцию:

getUserName() {
    echo $1 | cut -d : -f 1 | xargs basename
}

И передайте строку как параметр:

userName=$(getUserName "/var/cpanel/users/joebloggs:DNS9=domain.com")
echo $userName

Ответ 3

Как насчет sed? Это будет работать в одной команде:

sed 's#.*/\([^:]*\).*#\1#' <<<$string
  • # используются для разделителей регулярных выражений вместо /, поскольку в нем есть /.
  • .*/ захватывает строку до последней обратной косой черты.
  • \( .. \) обозначает группу захвата. Это \([^:]*\).
    • [^:] указывает любой символ _ за исключением двоеточия, а * означает ноль или более.
  • .* означает остальную часть строки.
  • \1 означает замену того, что было найдено в первой (и только) группе захвата. Это имя.

Здесь разбивка, соответствующая строке с регулярным выражением:

        /var/cpanel/users/           joebloggs  :DNS9=domain.com joebloggs
sed 's#.*/                          \([^:]*\)   .*              #\1       #'

Ответ 4

Использование одного sed

echo "/var/cpanel/users/joebloggs:DNS9=domain.com" | sed 's/.*\/\(.*\):.*/\1/'

Ответ 5

Используя один Awk:

... | awk -F '[/:]' '{print $5}'

То есть, используя разделитель полей как / или :, имя пользователя всегда находится в поле 5.

Чтобы сохранить его в переменной:

username=$(... | awk -F '[/:]' '{print $5}')

Более гибкая реализация с sed, которая не требует, чтобы имя пользователя было полем 5:

... | sed -e s/:.*// -e s?.*/??

То есть, удалите все из : и далее, а затем удалите все до последнего /. sed, вероятно, быстрее, чем awk, поэтому эта альтернатива определенно лучше.