wyodrębnij część ciągu za pomocą bash / cut / split


121

Mam taki ciąg:

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

Muszę wyodrębnić nazwę użytkownika ( joebloggs) z tego ciągu i zapisać ją w zmiennej.

Format łańcucha zawsze będzie taka sama, z wyjątkiem joebloggsi domain.comtak myślę łańcuch można podzielić dwa razy przy użyciu cut?

Pierwszy podział zostałby podzielony przez, :a pierwszą część przechowywalibyśmy w zmiennej, aby przekazać ją do drugiej funkcji podziału.

Drugi podział podzieliłby /i zapisze ostatnie słowo ( joebloggs) w zmiennej

Wiem, jak to zrobić w PHP przy użyciu tablic i podziałów, ale jestem trochę zagubiony w bashu.

Odpowiedzi:


333

Aby wyodrębnić joebloggsz tego ciągu w bash za pomocą rozwijania parametrów bez żadnych dodatkowych procesów ...

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

Nie zależy od joebloggsprzebywania na określonej głębokości ścieżki.


Podsumowanie

Przegląd kilku trybów rozszerzania parametrów, w celach informacyjnych ...

${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

Tak więc #środki dopasować od początku (myślę linii komentarzu) i %środków od końca. Jedna instancja oznacza najkrótszą, a dwie - najdłuższą.

Możesz uzyskać podciągi na podstawie pozycji za pomocą liczb:

${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)

Możesz również zamienić poszczególne ciągi lub wzorce za pomocą:

${MYVAR/search/replace}

patternJest w takim samym formacie jak plik nazwa-dopasowania, tak *(wszystkie znaki) jest powszechne, często następuje konkretnego symbolu podobnego /lub.

Przykłady:

Biorąc pod uwagę zmienną, taką jak

MYVAR="users/joebloggs/domain.com" 

Usuń ścieżkę pozostawiając nazwę pliku (wszystkie znaki aż do ukośnika):

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

Usuń nazwę pliku, pozostawiając ścieżkę (usuń najkrótsze dopasowanie po ostatnim /):

echo ${MYVAR%/*}
users/joebloggs

Pobierz tylko rozszerzenie pliku (usuń wszystko przed ostatnim okresem):

echo ${MYVAR##*.}
com

UWAGA: Aby wykonać dwie operacje, nie możesz ich łączyć, ale musisz przypisać je do zmiennej pośredniej. Aby uzyskać nazwę pliku bez ścieżki lub rozszerzenia:

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

Nie jestem pewien, czy jest to argument za lub przeciw kreatywnemu wykorzystaniu grepa, ale wypróbuj to z VAR = / tutaj / jest / a / path: with / a / colon / inside: DNS9 = domain.com
rici

2
Słodkie! Odbywa się to wewnątrz powłoki wykonawczej, dzięki czemu jest znacznie szybsze niż w przypadku innych poleceń.
stolsvik

3
@Fadi Musisz zamienić symbol wieloznaczny, aby pojawił się przed dwukropkiem i użyj #zamiast %. Jeśli chcesz tylko część za ostatnim dwukropkiem, użyj, ${MYVAR##*:}aby uzyskać część po pierwszym dwukropku, użyj${MYVAR#*:}
beroe.

4
Przyjacielu, nie wiesz, ile razy wracałem do tej odpowiedzi. Dziękuję Ci!
Joel B

1
Świetna odpowiedź! Pytanie: Gdyby mój wzorzec był zmienną, czy wpisałbym to w ten sposób, ${RET##*$CHOP}czy w ten ${RET##*CHOP}(lub w inny sposób)? EDYCJA: Wydaje się być pierwszym,${RET##*$CHOP}
Ctrl S

43

Zdefiniuj taką funkcję:

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

I przekaż łańcuch jako parametr:

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

1
Ta odpowiedź pomogła mi osiągnąć to, po co tu przyjechałem. Nie ma zaakceptowanych odpowiedzi i ta otrzymała mój głos za prostotą.
harperville

1
Jedyną poprawką jaką musiałem zrobić w powyższym poleceniu było usunięcie znaku „:” w ten sposób echo $1 | cut -d -f 1 | xargs. +1 za proste i zgrabne odpowiedzi.
Bhushan

20

A co z sedem? To zadziała w jednym poleceniu:

sed 's#.*/\([^:]*\).*#\1#' <<<$string
  • #Są wykorzystywane do regex dzielniki zamiast /ponieważ łańcuch ma /w nim.
  • .*/ przechwytuje ciąg do ostatniego odwrotnego ukośnika.
  • \( .. \)oznacza grupę przechwytywania. To jest \([^:]*\).
    • [^:]Mówi dowolny znak _except dwukropkiem, a *środki zero lub więcej.
  • .* oznacza resztę linii.
  • \1oznacza zastąpienie tego, co zostało znalezione w pierwszej (i jedynej) grupie przechwytywania. To jest nazwa.

Oto podział dopasowujący ciąg do wyrażenia regularnego:

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

Super miła sekcja!
kyb

11

Korzystanie z jednego seda

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

10

Korzystanie z jednego awk:

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

Oznacza to, że używa się również jako separatora pól / lub :, nazwa użytkownika jest zawsze w polu 5.

Aby zapisać go w zmiennej:

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

Bardziej elastyczna implementacja sed, która nie wymaga, aby nazwa użytkownika była polem 5:

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

Oznacza to, że usuń wszystko z :i poza, a następnie usuń wszystko aż do ostatniego /. sedjest prawdopodobnie szybszy niż awk, więc ta alternatywa jest zdecydowanie lepsza.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.