Dziękuję wszystkim. Skończyło się na użyciu „cut -c1-2”, szczerze mówiąc, nawet nie wiedziałem, że „cut” tam jest. Chciałbym powiedzieć, że mam duże doświadczenie w wierszu poleceń, ale najwyraźniej muszę się wiele nauczyć.
Greg,
1
@Greg, pamiętaj tylko, że cięcie jest uruchamiane jako oddzielny proces - będzie wolniejsze niż rozwiązanie wewnętrznego bash, które zamieściłem obok niego w mojej odpowiedzi. To nie ma znaczenia, chyba że przetwarzasz ogromne zestawy danych, ale musisz o tym pamiętać.
paxdiablo
Edytuj Właściwie myślę, że ta linia kodu zostanie prawdopodobnie wykonana około 50 000 razy na raport. Więc może po prostu skorzystam z wewnętrznej metody Bash - która, jak powiedziałeś, pozwoli zaoszczędzić trochę bardzo potrzebnych zasobów.
Prawdopodobnie najbardziej wydajną metodą, jeśli używasz bashpowłoki (i wydaje się, że tak jest, na podstawie twoich komentarzy), jest użycie wariantu podłańcucha rozwijania parametrów:
pax> long="USCAGol.blah.blah.blah"
pax> short="${long:0:2}"; echo "${short}"
US
Będą shortto pierwsze dwa znaki long. Jeśli longjest krótszy niż dwa znaki, shortbędzie identyczny.
Ta metoda w powłoce jest zwykle lepsza, jeśli zamierzasz to robić dużo (np. 50000 razy na raport, jak wspomniałeś), ponieważ nie ma narzutu związanego z tworzeniem procesu. Wszystkie rozwiązania korzystające z programów zewnętrznych będą cierpieć z powodu tego obciążenia.
Jeśli chcesz również zapewnić minimalną długość, możesz wyłożyć ją przed ręką za pomocą czegoś takiego:
pax> long="A"
pax> tmpstr="${long}.."
pax> short="${tmpstr:0:2}"; echo "${short}"
A.
Zapewniłoby to, że cokolwiek o długości mniejszej niż dwa znaki zostało dopełnione po prawej stronie kropkami (lub czymś innym, po prostu zmieniając znak używany podczas tworzenia tmpstr). Nie jest jasne, czy tego potrzebujesz, ale pomyślałem, że wstawię to dla kompletności.
Powiedziawszy to, istnieje wiele sposobów, aby to zrobić za pomocą programów zewnętrznych (na przykład, jeśli nie masz bashdostępnych), z których niektóre to:
short=$(echo "${long}"| cut -c1-2)
short=$(echo "${long}"| head -c2)
short=$(echo "${long}"| awk '{print substr ($0, 0, 2)}'
short=$(echo "${long}"| sed 's/^\(..\).*/\1/')
Pierwsze dwa ( cuti head) są identyczne dla ciągu jednowierszowego - w zasadzie oba zwracają po prostu pierwsze dwa znaki. Różnią się tym, cutże dadzą ci pierwsze dwa znaki w każdej linii i headdadzą ci pierwsze dwa znaki z całego wejścia
Trzecia używa funkcji awkpodłańcucha do wyodrębnienia pierwszych dwóch znaków, a czwarta używa sedgrup przechwytywania (przy użyciu ()i \1) do przechwycenia pierwszych dwóch znaków i zastąpienia nimi całego wiersza. Oba są podobne cut- dostarczają pierwsze dwa znaki z każdego wiersza na wejściu.
Nic z tego nie ma znaczenia, jeśli masz pewność, że dane wejściowe to jedna linia, wszystkie mają identyczny efekt.
Wolałbym użyć printf '%s'zamiast echow przypadku istnieją dziwne znaki w ciągu: stackoverflow.com/a/40423558/895245 Dla POSIX obsesję: head -cnie POSIX, cut -ca awk substrto, sed \1nie jestem pewien.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
@CiroSantilli 新疆 改造 中心 996ICU 六四 事件 używając printf, nie potrzebujesz nawet dodatkowego programu. Zobacz moją odpowiedź .
bschlueter
60
najłatwiej jest
${string:position:length}
Gdzie to wyodrębnia $lengthpodciąg z $stringat $position.
Jest to wbudowana funkcja bash, więc awk lub sed nie są wymagane.
To jest krótki, słodki i najłatwiejszy sposób na zdobycie podciągu.
ani627
34
Musisz zdobyć kilka dobrych odpowiedzi i pójdę z Basha wbudowane siebie, ale skoro pytasz o seda awki ( prawie ) nikt inny nie zaproponował rozwiązania oparte na nich, ofiaruję Ci te:
echo "USCAGoleta9311734.5021-120.1287855805"| sed 's/\(^..\).*/\1/'
To awkpowinno być dość oczywiste, ale oto wyjaśnienie sedjednego:
zastąp „s /”
grupa „()” składająca się z dwóch dowolnych znaków „..” zaczynająca się na początku wiersza „^”, po której następuje dowolny znak „”. powtórzone zero lub więcej razy „*” (ukośniki odwrotne są potrzebne do zmiany znaczenia niektórych znaków specjalnych)
przez „/” zawartość pierwszej (i jedynej w tym przypadku) grupy (w tym przypadku ukośnik odwrotny jest specjalnym znakiem ucieczki odnoszącym się do pasującego wyrażenia podrzędnego)
Jeśli chcesz używać skryptów powłoki i nie polegać na rozszerzeniach innych niż posix (takich jak tak zwane bashizmy), możesz użyć technik, które nie wymagają rozwidlania zewnętrznych narzędzi, takich jak grep, sed, cut, awk itp., sprawić, że twój skrypt będzie mniej wydajny. Może wydajność i przenośność Posix nie są ważne w twoim przypadku użycia. Ale jeśli tak jest (lub po prostu jest to dobry nawyk), możesz użyć następującej metody opcji rozwijania parametrów , aby wyodrębnić pierwsze dwa znaki zmiennej powłoki:
$ sh -c 'var=abcde; echo "${var%${var#??}}"'
ab
Wykorzystuje rozwinięcie parametrów „najmniejszy prefiks” w celu usunięcia pierwszych dwóch znaków (to jest ${var#??}część), a następnie rozwinięcie parametrów „najmniejszy sufiks” ( ${var%część) w celu usunięcia tego ciągu składającego się wyłącznie z dwóch pierwszych znaków z oryginału wartość.
Ta metoda została wcześniej opisana w odpowiedzi na pytanie „Powłoka = Sprawdź, czy zmienna zaczyna się od #”. Ta odpowiedź opisuje również kilka podobnych metod rozwijania parametrów, których można użyć w nieco innym kontekście niż ten, który odnosi się do pierwotnego pytania.
Najlepsza odpowiedź powinna być na górze. bez widelców, bez bashizmów. działa nawet z małymi muszlami, takimi jak myślnik.
exore
1
Jeśli twój system używa innej powłoki (nie bash), ale twój system ma bash, możesz nadal używać nieodłącznej manipulacji ciągiem bash, wywołując bashzmienną:
strEcho='echo ${str:0:2}'# '${str:2}' if you want to skip the first two characters and keep the rest
bash -c "str=\"$strFull\";$strEcho;"
biorąc pod uwagę, że prawdopodobnie będzie to wywoływał z muszli, lepszą formą byłobyperl -e 'print substr $ARGV[0], 0, 2' 'USCAGoleta9311734.5021-120.1287855805'
Odpowiedzi:
Prawdopodobnie najbardziej wydajną metodą, jeśli używasz
bash
powłoki (i wydaje się, że tak jest, na podstawie twoich komentarzy), jest użycie wariantu podłańcucha rozwijania parametrów:Będą
short
to pierwsze dwa znakilong
. Jeślilong
jest krótszy niż dwa znaki,short
będzie identyczny.Ta metoda w powłoce jest zwykle lepsza, jeśli zamierzasz to robić dużo (np. 50000 razy na raport, jak wspomniałeś), ponieważ nie ma narzutu związanego z tworzeniem procesu. Wszystkie rozwiązania korzystające z programów zewnętrznych będą cierpieć z powodu tego obciążenia.
Jeśli chcesz również zapewnić minimalną długość, możesz wyłożyć ją przed ręką za pomocą czegoś takiego:
Zapewniłoby to, że cokolwiek o długości mniejszej niż dwa znaki zostało dopełnione po prawej stronie kropkami (lub czymś innym, po prostu zmieniając znak używany podczas tworzenia
tmpstr
). Nie jest jasne, czy tego potrzebujesz, ale pomyślałem, że wstawię to dla kompletności.Powiedziawszy to, istnieje wiele sposobów, aby to zrobić za pomocą programów zewnętrznych (na przykład, jeśli nie masz
bash
dostępnych), z których niektóre to:Pierwsze dwa (
cut
ihead
) są identyczne dla ciągu jednowierszowego - w zasadzie oba zwracają po prostu pierwsze dwa znaki. Różnią się tym,cut
że dadzą ci pierwsze dwa znaki w każdej linii ihead
dadzą ci pierwsze dwa znaki z całego wejściaTrzecia używa funkcji
awk
podłańcucha do wyodrębnienia pierwszych dwóch znaków, a czwarta używased
grup przechwytywania (przy użyciu()
i\1
) do przechwycenia pierwszych dwóch znaków i zastąpienia nimi całego wiersza. Oba są podobnecut
- dostarczają pierwsze dwa znaki z każdego wiersza na wejściu.Nic z tego nie ma znaczenia, jeśli masz pewność, że dane wejściowe to jedna linia, wszystkie mają identyczny efekt.
źródło
printf '%s'
zamiastecho
w przypadku istnieją dziwne znaki w ciągu: stackoverflow.com/a/40423558/895245 Dla POSIX obsesję:head -c
nie POSIX,cut -c
aawk substr
to,sed \1
nie jestem pewien.najłatwiej jest
Gdzie to wyodrębnia
$length
podciąg z$string
at$position
.Jest to wbudowana funkcja bash, więc awk lub sed nie są wymagane.
źródło
Musisz zdobyć kilka dobrych odpowiedzi i pójdę z Basha wbudowane siebie, ale skoro pytasz o
sed
aawk
i ( prawie ) nikt inny nie zaproponował rozwiązania oparte na nich, ofiaruję Ci te:i
To
awk
powinno być dość oczywiste, ale oto wyjaśnieniesed
jednego:źródło
substr($0,1,2)
.Jeśli jesteś w środku
bash
, możesz powiedzieć:To może być właśnie to, czego potrzebujesz…
źródło
Po prostu grep:
źródło
-P
opcję, aby ją skrócić. Wszystkie wyrażenia regularne będą rozumieć ten wzorzec.Możesz użyć
printf
:źródło
colrm - usuwa kolumny z pliku
Aby zostawić pierwsze dwa znaki, po prostu usuń kolumny zaczynające się od 3
źródło
Dość późno, ale oto jest
Lub
Lub
źródło
Jeśli chcesz używać skryptów powłoki i nie polegać na rozszerzeniach innych niż posix (takich jak tak zwane bashizmy), możesz użyć technik, które nie wymagają rozwidlania zewnętrznych narzędzi, takich jak grep, sed, cut, awk itp., sprawić, że twój skrypt będzie mniej wydajny. Może wydajność i przenośność Posix nie są ważne w twoim przypadku użycia. Ale jeśli tak jest (lub po prostu jest to dobry nawyk), możesz użyć następującej metody opcji rozwijania parametrów , aby wyodrębnić pierwsze dwa znaki zmiennej powłoki:
Wykorzystuje rozwinięcie parametrów „najmniejszy prefiks” w celu usunięcia pierwszych dwóch znaków (to jest
${var#??}
część), a następnie rozwinięcie parametrów „najmniejszy sufiks” (${var%
część) w celu usunięcia tego ciągu składającego się wyłącznie z dwóch pierwszych znaków z oryginału wartość.Ta metoda została wcześniej opisana w odpowiedzi na pytanie „Powłoka = Sprawdź, czy zmienna zaczyna się od #”. Ta odpowiedź opisuje również kilka podobnych metod rozwijania parametrów, których można użyć w nieco innym kontekście niż ten, który odnosi się do pierwotnego pytania.
źródło
Jeśli twój system używa innej powłoki (nie
bash
), ale twój system mabash
, możesz nadal używać nieodłącznej manipulacji ciągiembash
, wywołującbash
zmienną:źródło
bash
wtedy, gdy jeszcze jej nie używasz.Dla zabawy dodam jeszcze kilka, że choć są zbyt skomplikowane i bezużyteczne, nie zostały wymienione:
źródło
źródło
jeśli mystring = USCAGoleta9311734.5021-120.1287855805
wydrukowałoby US
gdzie 0 to pozycja początkowa, a 2 to jak odczytać wiele znaków
źródło
awk
. Przepraszam, na początku nie mogłem powiedzieć.Czy to jest to, czego szukasz?
ref: substr
źródło
perl -e 'print substr $ARGV[0], 0, 2' 'USCAGoleta9311734.5021-120.1287855805'