Usando sed ottenere sottostringhe tra due virgolette doppie


13

Ho un file

xyz... rsync: "/home/path/to/file": Permission denied (13) rsync:
"/home/path/to/file1": Permission denied (13) rsync:
"/home/path/to/file2": Permission denied (13) rsync:
"/home/path/to/file3": Permission denied (13)

Ora voglio estrarre solo i percorsi dei file e archiviarli su un altro file. Il file di output è come:

/home/path/to/file 
/home/path/to/file1 
/home/path/to/file2
/home/path/to/file3

Usando sed o awk come posso fare questo?

Ho provato sed -n '/"/,/"/p' myfile ma non funziona.


3
A chi vota per chiudere - Come può essere fuori tema? Si tratta di programmazione shell! È PROGRAMMAZIONE che è ON THEIC per Stack Overflow!
Jonathan Leffler

2
Benvenuto in Stack Overflow. Come potete vedere, occasionalmente abbiamo problemi con le persone che hanno prurito alle dita del grilletto che chiudono domande perfettamente buone (come questa) con cattive ragioni per la chiusura. Non succede spesso (o non riesco a vedere il problema in tempo così spesso), ma succede. Non dimenticare di leggere il FAQ prima troppo a lungo.
Jonathan Leffler

Risposte:


17

È possibile reindirizzare lo stderr del comando rsync a uno script awk:

awk -F '"' '{print $2}' 

O ad un comando di taglio come questo:

cut -d'"' -f2

2
Oppure, più breve: cut -d\" -f2

@ AndersJohansson: Grazie ho aggiunto il comando di taglio per rispondere pure.
anubhava

Penso che questo non funzionerà ... come puoi vedere il numero del campo del percorso del file non è fisso $ 2 o f2 .. Grazie!

In realtà rsync scriverà sempre traiettoria prima tra i file " e " su stderr.
anubhava

1
@ Jam88: In realtà, funzionerà a causa del modo in cui è stato scritto da anubbhava. Il delimitatore di campo è impostato su virgolette. Ciò significa che tutto fino alla prima citazione doppia (probabilmente una stringa vuota) lo è $1; tutto tra la prima e la seconda doppia citazione è $2; e tutto dopo la seconda doppia citazione è in $3 ( $4, ...). Il nome del file è (apparentemente) sempre tra le prime due virgolette doppie, quindi questa soluzione dovrebbe funzionare (e lo ha fatto quando l'ho testato).
Jonathan Leffler

6

utilizzando sed:

sed 's/^[^"]*"\([^"]*\)".*/\1/'

Quello che cerca: all'inizio della linea, una serie di non citazioni, una doppia citazione, cattura una serie di non citazioni, una doppia citazione e qualsiasi altra cosa sulla linea, e la sostituisce con il materiale catturato.

$ sed 's/^[^"]*"\([^"]*\)".*/\1/' <<'EOF'
> xyz... rsync: "/home/path/to/file": Permission denied (13) rsync:
> "/home/path/to/file1": Permission denied (13) rsync:
> "/home/path/to/file2": Permission denied (13) rsync:
> "/home/path/to/file3": Permission denied (13)
> EOF
/home/path/to/file
/home/path/to/file1
/home/path/to/file2
/home/path/to/file3
$

Prova su RHEL 5 Linux con GNU sed, ma utilizzando solo le funzionalità che avrebbero funzionato nella versione UNIX ™ della 7 ° edizione di sed.

Per inciso, un modo leggermente più semplice per farlo è con due comandi sostitutivi; cambia tutto fino a includere la prima virgoletta doppia su una stringa vuota (questa è una sequenza di zero o più virgolette seguite da una virgola doppia); cambia tutto dopo quello che è ora il primo doppio preventivo a zero:

sed 's/^[^"]*"//; s/".*//'

Per inciso, il comando che hai provato (`sed -n '/" /, / "/ p') stampa da una riga contenente una virgola doppia alla riga successiva contenente una virgoletta doppia, senza modificare le righe. Questo era il motivo per cui non sembrava funzionare per te: ha fatto ciò che hai chiesto, ma ciò che gli hai chiesto di fare non era quello che intendevi chiederlo.

Per quanto riguarda l'efficienza, è improbabile che ci sia una differenza misurabile nelle prestazioni. In termini di facilità di manutenzione, sospetto che quest'ultimo sia meno oneroso per le cellule cerebrali.


0

Se la tua versione di grep supporta Perl-regexp:

grep -oP '(?<=")/home/.*?(?=")' file >> anotherfile

risultati:

/home/path/to/file
/home/path/to/file1
/home/path/to/file2
/home/path/to/file3

Potresti anche renderlo meno severo, per abbinare qualsiasi cosa tra i doppi se desideri:

grep -oP '(?<=")[^"]*' file >> anotherfile

Hai bisogno di fare il .* non-goloso con .*? nel caso ci fosse una doppia virgoletta in più in coda? O usare [^"]* al posto di .*?
Jonathan Leffler

@ JonathanLeffler: buon punto. Grazie!
Steve

@steve: Grazie! Questo farà!
XemX

@ Jam88: Nessun problema! Non per aver accettato una risposta. Puoi scegliere la tua risposta preferita cliccando il segno di spunta direttamente a sinistra. Saluti.
Steve

-1

Utilizza il & gt; & gt; operatore per salvare qualsiasi output in un file.

Piace

grep -r "pattern" * >> file.txt

Quindi basta cambiarlo per il tuo scenario specifico usando sed aggiungendo

>> filename

al comando


Il grep -r fa una ricerca ricorsiva attraverso tutte le directory elencate negli argomenti ( * ). Non è chiaro quale schema tu abbia in mente, ma grep prenderà l'intera linea. Lo scopo dell'esercizio è raccogliere informazioni da una parte di una linea. Se stai usando GNU grep, ci sono modi per farlo ( -o ); questi sono non standard (tranne nella misura in cui GNU definisce uno standard de facto). Allo stesso modo con l'uso delle espressioni regolari PCRE; quelli sono un'altra estensione GNU. Stanno bene se hai GNU grep e non ha intenzione di lavorare su piattaforme in cui GNU grep non è disponibile per impostazione predefinita.
Jonathan Leffler

Mi dispiace di averlo perso, ho pensato che volesse sapere in generale cosa fare per mettere l'output in un file, e grep era solo un esempio.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.