витягнути частину струни за допомогою bash / cut / split


121

У мене є такий рядок:

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

Мені потрібно витягнути ім'я користувача ( joebloggs) з цього рядка і зберегти його в змінній.

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

Перший спліт розділиться на, :і ми збережемо першу частину в змінній, щоб перейти до другої функції розділення.

Другий розділ розділиться /і збереже останнє слово ( joebloggs) у змінну

Я знаю, як це зробити у php, використовуючи масиви та розбиття, але я трохи втрачений у баші.

Відповіді:


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 = / тут / є / а / шлях: з / a / двокрапка / всередині: DNS9 = domain.com
rici

2
Солодке! І це робиться всередині виконуючої оболонки, тим самим шлях швидше, ніж ті, що використовують інші команди.
stolsvik

3
@Fadi Ви повинні переключити підстановку, щоб перейти до товстої кишки, і використовувати #замість неї %. Якщо ви хочете лише частину після останньої двокрапки, використовуйте її, ${MYVAR##*:}щоб отримати частину після першої двокрапки, використовуйте${MYVAR#*:}
beroe

4
Друже, ти не знаєш, скільки разів я повертався до цієї відповіді. Дякую!
Джоель Б

1
Чудова відповідь! Питання: Якби мій шаблон був змінною, я би ввів його так ${RET##*$CHOP}чи подібним чином ${RET##*CHOP}(чи іншим способом)? EDIT: Здається, колишній,${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 для простих і акуратних анс.
Бхушань

20

А що з седом? Це буде працювати в одній команді:

sed 's#.*/\([^:]*\).*#\1#' <<<$string
  • Вони #використовуються для розділювачів регулярних виразів замість того, /що /в ньому є рядок .
  • .*/ захоплює рядок до останньої косої риски.
  • \( .. \)позначає групу захоплення. Це \([^:]*\).
    • [^:]Каже будь-який символ _except двокрапка, і *означає нуль або більше.
  • .* означає решту рядка.
  • \1означає замінити те, що було знайдено в першій (і єдиній) групі захоплення. Це ім'я.

Ось розбивка, що відповідає рядку з регулярним виразом:

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

Супер приємна розсічка!
киб


10

Використання одного Awk:

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

Тобто, використовуючи як роздільник поля або, /або :ім'я користувача завжди знаходиться в полі 5.

Щоб зберегти його у змінній:

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

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

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

Тобто, видаліть усе з :і за його межами, а потім видаліть усе до останнього /. sedнапевно, теж швидше awk, тому така альтернатива, безумовно, краща.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.