извлечь часть строки с помощью bash / cut / split

122

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

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

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

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

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

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

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

Крэйг Эдмондс
источник

Ответы:

333

Чтобы извлечь 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нахождения на определенной глубине пути.


Резюме

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

${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
берый
источник
Я не уверен, является ли это аргументом за или против творческого использования grep, но попробуйте его с помощью VAR = / here / is / a / path: with / a / двоеточие / внутри: DNS9 =
domain.com
2
Сладкий! И это делается внутри исполняющейся оболочки, поэтому намного быстрее, чем те, которые используют другие команды.
stolsvik
3
@Fadi Вы должны переключить подстановочный знак, чтобы он стоял перед двоеточием, и использовать #вместо %. Если вам нужна только часть после самого последнего двоеточия, используйте, ${MYVAR##*:}чтобы получить часть после первого двоеточия, используйте${MYVAR#*:}
beroe
4
Друг, ты не знаешь, сколько раз я возвращался к этому ответу. Спасибо!
Joel B
1
Отличный ответ! Вопрос: Если бы мой шаблон был переменной, я бы напечатал его так ${RET##*$CHOP}или так ${RET##*CHOP}(или другим способом)? РЕДАКТИРОВАТЬ: Кажется, первое,${RET##*$CHOP}
Ctrl S
43

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

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

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

userName=$(getUserName "/var/cpanel/users/joebloggs:DNS9=domain.com")
echo $userName
Стефано Санфилиппо
источник
1
Этот ответ помог мне достичь того, ради чего я сюда пришел. Нет принятых ответов, и я проголосую за простоту.
harperville
1
Единственное исправление, которое мне пришлось внести в приведенную выше команду, - это удаление символа «:», как это echo $1 | cut -d -f 1 | xargs. +1 за простые и аккуратные ответы.
Bhushan
20

А как насчет sed? Это будет работать с помощью одной команды:

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

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

        /var/cpanel/users/           joebloggs  :DNS9=domain.com joebloggs
sed 's#.*/                          \([^:]*\)   .*              #\1       #'
Дэвид В.
источник
Супер красивое вскрытие!
kyb 06
11

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

echo "/var/cpanel/users/joebloggs:DNS9=domain.com" | sed 's/.*\/\(.*\):.*/\1/'
Янн Мойсан
источник
10

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

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

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

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

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

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

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

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

Янош
источник