2009-09-10 14 views
76

Jestem nowy dla sed i awk - więc nie jestem do końca pewien, który z nich jest najbardziej skuteczny.Wyodrębnianie pierwszych dwóch znaków ciągu znaków (Shell Scripting)

Szukam wyodrębnić pierwsze dwie litery ciągu. Mogłabym to zrobić, gdyby za każdym razem były takie same, ale nie potrafię wymyślić, jak po prostu powiedzieć:

Podjąć n pozycji tego łańcucha z tego większego ciągu x.

IE.

 
USCAGoleta9311734.5021-120.1287855805 = US 
+3

Dziękuję wszystkim. Skończyło się na tym, że użyłem "cut -c1-2", szczerze mówiąc, nie wiedziałem nawet, że istnieje "cut". Chciałbym powiedzieć, że jestem dość doświadczony na linii poleceń - ale najwyraźniej muszę się jeszcze wiele nauczyć. – Greg

+1

@Greg, pamiętaj tylko, że cięcie jest uruchamiane jako oddzielny proces - będzie wolniejsze niż rozwiązanie wewnętrzne bash, które umieściłem obok niego w mojej odpowiedzi. Nie ma to znaczenia, chyba że przetwarzasz ogromne zbiory danych, ale musisz o tym pamiętać. – paxdiablo

+0

[Edytuj] Właściwie, myślę, że ta linia kodu zostanie prawdopodobnie wykonana około 50 000 razy na raport. Mogę więc po prostu zastosować wewnętrzną metodę Bash - która, jak powiedziałeś, pozwoli zaoszczędzić trochę potrzebnych zasobów. – Greg

Odpowiedz

29

Najłatwiej jest

${string:position:length} 

Gdzie ten wydobywa $length podciąg z $string na $position.

Jest to wbudowane bash, więc awk lub sed nie jest wymagany.

+0

To jest krótki, słodki i najprostszy sposób uzyskać podciąg. – user1336087

108

Prawdopodobnie najbardziej efektywny sposób, jeśli używasz powłoki bash (i wydaje się, w oparciu o komentarze), jest użycie wariantu podciąg ekspansji parametr:

pax> long="USCAGol.blah.blah.blah" 
pax> short="${long:0:2}" ; echo "${short}" 
US 

Spowoduje to ustawienie short jako pierwszych dwóch znaków long. Jeśli long jest krótszy niż dwa znaki, short będzie identyczny.

Ta metoda działająca w powłoce jest zwykle lepsza, jeśli zamierzasz robić to dużo (na przykład 50 000 razy na raport, o ile wspominasz), ponieważ nie ma kosztów związanych z tworzeniem procesów. Wszystkie rozwiązania korzystające z programów zewnętrznych będą cierpieć z powodu tego obciążenia.

Jeśli również chciał zapewnić minimalną długości, można pad go przed parze z czymś takim:

pax> long="A" 
pax> tmpstr="${long}.." 
pax> short="${tmpstr:0:2}" ; echo "${short}" 
A. 

Zapewni to, że nic mniej niż dwóch znaków zostało wyściełane na prawo z 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.


Mimo, że istnieją różne sposoby, aby to zrobić z programów zewnętrznych (takich jak, jeśli nie masz bash dostępne dla użytkownika), z których niektóre są:

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 (cut i head) są identyczne dla ciągu jednoliniowego - w zasadzie oba dają tylko pierwsze dwa znaki. Różnią się one tym cut daje dwa pierwsze znaki każdego wiersza i head daje dwa pierwsze znaki całej wejścia

Trzeci wykorzystuje funkcję awk podciąg do wyodrębnienia dwóch pierwszych znaków i czwarty używa sed grup przechwytujących (używając () i \1), aby przechwycić pierwsze dwa znaki i zastąpić je całą linią.Oba są podobne do cut - dostarczają pierwsze dwa znaki każdej linii na wejściu.

Nie ma to znaczenia, jeśli masz pewność, że dane wejściowe są pojedynczą linią, wszystkie mają identyczny efekt.

0

Czy to jest twoje po?

my $string = 'USCAGoleta9311734.5021-120.1287855805'; 

my $first_two_chars = substr $string, 0, 2; 

ref: substr

+1

biorąc pod uwagę, że prawdopodobnie wywoła to z powłoki, lepszym formularzem byłoby 'perl -e 'print substr $ ARGV [0], 0, 2' 'USCAGoleta9311734.5021-120.1287855805'' –

0

jeśli mystring = USCAGoleta9311734.5021-120.1287855805

print substr(mystring,0,2) 

by wydrukować US

gdzie 0 jest pozycja początkowa i 2 jest jak meny znaków czytać

+0

Powiedz ... Czy to nie GW-BASIC? Och, czekaj, to jest 'awk'. Przepraszam, nie mogłem powiedzieć na początku. –

0
perl -ple 's/^(..).*/$1/' 
+0

Zapomniałeś o tym napisać. –

+0

Nie, ja nie ... brzmi STDIN – dsm

29

pan zdobyć kilka dobrych odpowiedzi i pójdę z Basha wbudowane siebie, ale skoro pytasz o sed i awk i (prawie) nikt oferowane rozwiązania oparte na nich, ofiaruję Ci te:

echo "USCAGoleta9311734.5021-120.1287855805" | awk '{print substr($0,0,2)}' 

i

echo "USCAGoleta9311734.5021-120.1287855805" | sed 's/\(^..\).*/\1/' 

awk jeden powinien być dość oczywiste, ale tu jest wyjaśnienie sed jednym:

  • podstawienie "s /"
  • grupa "()" dwóch dowolnych znaków ".." zaczynających się na początku wiersza "^", po którym następuje dowolny znak "."powtórzone zero lub więcej razy" * "(do uniknięcia niektórych znaków specjalnych potrzebne są odwrotne ukośniki)
  • przez"/"zawartość pierwszej (i tylko w tym przypadku) grupy (tutaj odwrotny ukośnik jest specjalnym uciec odnosząc się do dopasowania sub-expression)
  • zrobione "/"
3

colrm - usunąć kolumny z pliku

aby opuścić dwa pierwsze znaki, po prostu usunąć kolumny począwszy od 3

cat file | colrm 3 
3

Jeśli jesteś w bash, można powiedzieć:

bash-3.2$ var=abcd 
bash-3.2$ echo ${var:0:2} 
ab 

To może być tylko to, czego potrzebujesz ...

+1

Niestety - nie widziałem, że Pax już to opublikował. –

+0

najłatwiejsza i najprostsza odpowiedź! działał jak czar – aloha

3

Dość późno, ale rzeczywiście tu jest

sed 's/.//3g' 

Albo

awk NF=1 FPAT=.. 

Lub

perl -pe '$_=unpack a2' 
3

Wystarczy grep:

echo 'abcdef' | grep -Po "^.."  # ab 
1

Jeśli system wykorzystuje inną powłokę (nie bash), ale system ma bash, możesz nadal korzystać z wrodzoną manipulacji ciąg bash powołując bash ze zmienną:

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;" 
+0

Używa tej samej metody co [główna odpowiedź] (http://stackoverflow.com/a/1405641/393280), odwołując się tylko do 'bash', jeśli jeszcze jej nie używasz. – palswim

+0

Niestety, przychodzi to ze wszystkimi kosztami wywoływania innego procesu, ale czasami takie obciążenie nie ma znaczenia, jak prostota i znajomość. – palswim

Powiązane problemy