Wiem, że cut
polecenie może wydrukować pierwsze n
znaki ciągu, ale jak wybrać ostatnie n
znaki?
Jeśli mam ciąg ze zmienną liczbą znaków, w jaki sposób mogę wydrukować tylko trzy ostatnie znaki ciągu. na przykład.
Wymagana „nieograniczona” moc wyjściowa to „ted” Wymagane wyjście „987654” to „654” Wymagane wyjście „123456789” to „789”
text-processing
cut
odyseja
źródło
źródło
grep -o '.\{3\}$'
echo "unlimited" | python -c "print raw_input()[-3:]"
"echo unlimited" | java -jar EnterpriseWordTrimmer.jar
, ale nie sądzę, że naprawdę ciężko jest wprowadzić cięższy język do manipulacji postaciami.java -server -Xms300M -Xmx3G -XX:+UseParallelGC -cp /path/to/all/the/jars/ -Dinput.interactive=false -Dinput.pipe=true -Dconfig.file=/path/to/config/last-three-letters.cfg -jar ...
grep -o -P '.{0,3}$'
wypisze 3 ostatnie znaki, nawet jeśli linia ma mniej niż 3 znaki.-P
pozwala uniknąć ucieczki z aparatu ortodontycznego.Prostota - ogon
Nie powinniśmy potrzebować wyrażenia regularnego ani więcej niż jednego procesu, aby policzyć znaki.
Polecenie
tail
, często używane do wyświetlania ostatnich linii pliku, ma opcję-c
(--bytes
), która wydaje się być właściwym narzędziem do tego:(Gdy jesteś w powłoce, sensowne jest użycie metody takiej jak w odpowiedzi mikeserv, ponieważ oszczędza to rozpoczęcia procesu
tail
.)Prawdziwe znaki Unicode?
Teraz pytasz o ostatnie trzy postacie ; Nie to daje ci ta odpowiedź: wyświetla trzy ostatnie bajty !
Tak długo, jak każdy znak ma jeden bajt,
tail -c
po prostu działa. Dzięki czemu może być używany, jeśli zestaw znakówASCII
,ISO 8859-1
lub jego wariant.Jeśli masz wejście Unicode, jak we wspólnym
UTF-8
formacie, wynik jest nieprawidłowy:W tym przykładzie użycie
UTF-8
greckich znaków alfa, beta i gamma ma dwa bajty:Ta opcja
-m
może przynajmniej liczyć prawdziwe znaki Unicode:Ok, więc ostatnie 6 bajtów da nam ostatnie 3 znaki:
Więc
tail
nie obsługuje przenoszenia ogólne znaki, i to nawet nie próbować (patrz poniżej): Obsługuje linie zmienne wielkości, ale nie ma znaków o zmiennej wielkości.Ujmijmy to w następujący sposób:
tail
jest odpowiedni dla struktury problemu do rozwiązania, ale zły dla rodzaju danych.Coreutils GNU
Patrząc dalej, okazuje się, że thee coreutils GNU zbiór podstawowych narzędzi podoba
sed
,ls
,tail
acut
nie jest jeszcze w pełni umiędzynarodowione. Dotyczy to głównie obsługi Unicode.Na przykład
cut
byłby dobrym kandydatem do użycia zamiast ogona tutaj do wspierania postaci; Ma opcje pracy na bajtach lub znakach,-c
(--bytes
) i-m
(--chars
);Tyle, że
-m
/--chars
od wersjicut (GNU coreutils) 8.21
2013nie jest zaimplementowany!
Od
info cut
:Zobacz także tę odpowiedź na Nie możesz używać `cut -c` (` --characters`) z UTF-8? .
źródło
cut
, że nie dotyczy to tylko twojego i Glenna Jackmana .tail
powinny zajmować się bajtami, a nie znakami. Kiedyś zrobiłem łatkę, aby dodać nową opcję, aby również wybrać postacie, ale wierzę, że nigdy się nie połączyłem: - /tail -c3 -n10 /var/log/syslog
tail -c3 -n10 /var/log/syslog
prosi o ostatnie 10 wierszy i to działa dla mnie. Korzystasz z opcji-c3
, a następnie z opcji sprzecznej-n10
. Późniejsza opcja ma priorytet.Jeśli tekst jest w zmiennej powłoki o nazwie
STRING
, można to zrobić w sposóbbash
,zsh
lubmksh
zapłacić:Lub
który ma również tę zaletę, że współpracuje z ksh93, skąd pochodzi ta składnia.
Chodzi o to, że
:
trzeba go oddzielić od-
, w przeciwnym razie staje się${var:-default}
operatorem powłoki Bourne'a.Równoważna składnia w powłokach
zsh
lubyash
to:źródło
${STRING:(-3):3}
(określając pole długości ),${STRING: -3}
(ze spacją między:
i-
), lub${STRING: -3:3}
.3
jest nieco dyskusyjne, ponieważ wymaga „trzech znaków od trzeciego od ostatniego znaku włącznie”, co w praktyce jest identyczną operacją jak „Wszystkie postacie od trzeciego od ostatniego , włącznie".Używanie
awk
:źródło
Jeśli ciąg znajduje się w zmiennej, możesz:
To usuwa trzy ostatnie znaki z wartości
$var
like:... a potem zdziera z głowy
$var
wszystko, ale to, co zostało po prostu pozbawione:Ta metoda ma swoje zalety i wady. Z drugiej strony jest w pełni przenośny dla POSIX i powinien działać w każdej nowoczesnej powłoce. Ponadto, jeśli
$var
nie zawierają co najmniej trzy znaki nic ale spływu\n
ewline zostanie wydrukowany. Z drugiej strony, jeśli chcesz wydrukować go w takim przypadku, potrzebujesz dodatkowego kroku, takiego jak:W ten sposób
$last3
jest zawsze pusty, jeśli$var
zawiera 3 lub mniej bajtów. I$var
jest zawsze zastępowany,$last3
jeśli$last3
jest pusty lubunset
- i wiemy, że nie jest tak,unset
ponieważ właśnie go ustawiliśmy.źródło
printf
ciągów formatu?${VARNAME:(-3)}
(zakładającbash
)?bash
jak w każdej innej powłoce, która twierdzi, że jest zgodna z POSIX.csh
to nie wśród nowoczesnych, zgodnych z POSIX muszli Wspomnę tu, niestety. Modelowana jest specyfikacja powłoki POSIXksh
, która modelowała się po kombinacji obucsh
i tradycyjnych powłok w stylu Bourne'a.ksh
zawiera zarównocsh
doskonałą funkcję kontroli zadań, jak i przekierowanie we / wy starych stylów Bourne'a. Dodał także pewne rzeczy - takie jak koncepcje manipulacji ciągami, które pokazałem powyżej.csh
Przykro mi to mówić, ale to nie będzie działać w żadnym tradycyjnym, o ile mi wiadomo.Możesz to zrobić, ale jest to trochę ... nadmierne:
źródło
Kuloodporne rozwiązanie dla ciągów utf-8:
Albo użyj:
aby zapobiec nieprawidłowej obsłudze danych.
Przykład:
Wyprowadza coś takiego:
Nie zależy od ustawień regionalnych (tzn. Działa z
LC_ALL=C
).Bash
,sed
,grep
,awk
,rev
Wymagają mniej więcej tak:LC_ALL=en_US.UTF-8
Wspólne rozwiązanie:
Możesz wykryć kodowanie za pomocą uchardet . Zobacz także powiązane projekty .
Możesz dekodować / kodować za pomocą Encode w Perlu, kodeków w Pythonie 2.7
Przykład :
Wyodrębnij ostatnie trzy znaki z ciągu utf-16le i przekonwertuj te znaki na utf-8
Zobacz także: perlunitut , Python 2 Unicode HOWTO
źródło
echo
jest twoje kuloodporne źródło?decode/encode
jest moim kuloodpornym źródłem. Oczyściłem moją odpowiedź.LC_ALL=C
ponieważ jest to bardzo „głupie” ustawienie, ale może się zepsuć, gdy spróbujesz przekazać ciąg UTF-8 do SHIFT-5 lub ciąg SHIFT-5 do KOI8 itp.perl -CAO -e 'print substr($ARGV[0], -3)'
działa dobrze.A
oczekuje się, że elementy @ARGV będą ciągami kodowanymi w UTF-8,O
STDOUT będzie w UTF-8.utf8_str
Co powiesz na użycie „expr” lub „rev”?
Odpowiedź podobna do tej udzielonej przez @ G-Man :
expr "$yourstring" : '.*\(...\)$'
Ma tę samą wadę, co rozwiązanie grep.Dobrze znaną sztuczką jest łączenie „cięcia” z „obrotem”:
echo "$yourstring" | rev | cut -n 1-3 | rev
źródło
rev
Rozwiązanie wygląda jak Glenn JackmanaUzyskaj rozmiar łańcucha za pomocą:
Następnie zdobądź podłańcuch ostatniego n znaku:
Na przykład:
dałby:
źródło
tail -n 1 revisions.log | awk '{print substr (0 USD, 0, długość (0 USD) - (długość (0 USD) -13))}'
Jeśli chcesz wydrukować pierwsze trzynaście znaków od samego początku
źródło
printf nie będzie działać, jeśli w łańcuchu znajdują się spacje.
Poniżej kodu dla łańcucha ze spacją
źródło
printf
nie działa, robisz coś bardzo złego.printf $str
(zamiastprintf "$str"
lubprintf '%s' "$str"
). I tak,printf $str
jest bardzo źle. (echo -n $str
nie jest dużo lepszy.)