2017-02-21 5 views
0

Ich versuche, den Speicherort aller Instanzen einer Zeichenfolge in einer bestimmten Datei zu finden; Der Code, den ich gerade ausführe, gibt jedoch nur den Ort der ersten Instanz zurück und hält dann dort an. Hier ist, was ich zur Zeit läuft:Suchen nach Zeichen aller Instanzen einer Zeichenfolge in Bash

str=$(cat temp1.txt) 
tmp="${str%%<C>*}" 

if [ "$tmp" != "$str" ]; then 
echo ${#tmp} 
fi 

Die Datei ist nur eine Zeile der Zeichenfolge und ich würde es zeigen, aber die Formatfragen müssen Sie wird nicht zulassen, dass mir die richtige Menge von Räumen hinzuzufügen zwischen jedes Zeichen.

+1

Beispiel Eingabe und erwartete Ausgabe, bitte. – chepner

+0

Ich habe versucht, die Beispieleingabe zu senden, aber die Formatierung der Frage erlaubt mir nicht, den richtigen Abstand zwischen den Zeichen anzuwenden. Es ist im Wesentlichen eine Zeile mit mehrere Male mit verschiedenen Mengen an Leerzeichen zwischen jedem. Ich brauche nur den Ort jedes Auftretens. – Zach

Antwort

1

Ich bin nicht sicher von vielen Details Ihrer Anforderungen, aber dies ist ein awk Einzeiler:

awk -vRS='<C>' '{printf("%u:",a+=length($0));a+=length(RS)}END{print ""}' temp1.txt 

ist es mit einer aktuellen Eingabezeile Lassen Sie testen:

$ awk -vRS='<C>' \ 
    '{printf("%u:",a+=length($0));a+=length(RS)}END{print ""}' \ 
    <<<" <C>  <C> " 
4:14:20: 

Dieses Mittel : Die erste <C> ist bei Byte 4, die zweite <C> ist bei Byte 14 (einschließlich der drei Bytes der ersten <C>), und die gesamte Zeile ist 20 Byte lang (einschließlich final Newline).

Ist das was du willst?

Erklärung

Wir setzen (-v) voneinander zu trennen sind (RS) als <C>. Dann behalten wir eine Variable a mit der Anzahl aller bisher verarbeiteten Bytes. Für jede "Zeile" (d. H. <C> - getrennte Teilstrings) addieren wir die Länge der aktuellen Zeile zu a, printf mit einem geeigneten Format "%u:" und erhöhen a um die Länge des Separators, der die aktuelle Zeile beendete. Da bisher noch keine Zeilenumbrüche gedruckt wurden, gibt es bei der END we print einen leeren String, der ein Idiom ist, um einen finalen Zeilenumbruch auszugeben.

+0

Ich habe das ausgeführt und mein Computer scheint die Trennzeichen -v abzulehnen: "awk: invalid -v Option" – Zach

+0

Missachtung, es gab einen Tippfehler und es hat funktioniert! Ich danke dir sehr! – Zach

0

Schauen Sie sich die im Grunde die gleiche Frage gestellt here.

Insbesondere Ihre Frage kann für mehrere Instanzen dank Benutzer JRFerguson Antwort mit Perl beantwortet werden.

EDIT: Ich fand eine andere Lösung, die nur den Trick here tun könnte. (. Die Hauptfrage und Antwort Post ist here gefunden)

ich die Schale von KSH zu bash geändert, geändert, um die gesuchte Zeichenkette mehrere <C> enthalten ist, um besser eine Antwort zu zeigen die Frage, und nannte sie ‚Tester‘: Diese

#!/bin/bash 
printf '%s\n' '<C>abc<C>xyz<C>123456<C>zzz<C>' | awk -v s="$1" ' 
{  d = "" 
     for(i = 1; x = index(substr($0, i), s); i = i + x + length(s) - 1) { 
       printf("%s%d", d, i + x - 1) 
       d = ":" 
     } 
     print "" 
}' 

ist, wie ich es lief:

$ tester '<C>' 
1:7:13:22:28 

ich habe nicht den Code heraus (ich mag wissen, warum es funktioniert), aber es scheint zu funktionieren! Es wäre schön, eine Erklärung und einen eleganten Weg zu finden, um Ihre Zeichenfolge in dieses Skript einzufügen. Prost.

+0

Ich habe diese Frage tatsächlich benutzt, um meinen ersten Versuch mit diesem Code zu schreiben. Es gibt nur das erste Vorkommen der Zeichenfolge zurück, nach der ich suche. – Zach

Verwandte Themen