Za pomocą sed uzyskaj podciąg między dwoma podwójnymi cudzysłowami

14

Mam plik

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)

Teraz chcę wyodrębnić tylko ścieżki plików i zapisać je w innym pliku. Plik wyjściowy jest jak:

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

Używając sed lub awk, jak mogę to zrobić?

Próbowałem, sed -n '/"/,/"/p' myfileale to nie działa.

XemX
źródło
3
Do osób głosujących na zakończenie - jak to może być nie na temat? Chodzi o programowanie powłoki! To jest PROGRAMOWANIE, KTÓRE JEST NA TEMAT Przepełnienia stosu!
Jonathan Leffler,
2
Witamy w Stack Overflow. Jak widać, od czasu do czasu mamy problemy z tym, że ludzie z swędzącym palcem spustowym zamykają idealnie dobre pytania (takie jak to) ze złymi powodami zamknięcia. To nie zdarza się tak często (lub, nie dostaję tego problemu tak często), ale tak się dzieje. Nie zapomnij przeczytać zbyt często FAQ .
Jonathan Leffler,

Odpowiedzi:

17

Możesz potokować stderr polecenia rsync do skryptu awk:

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

Lub do polecenia cięcia takiego:

cut -d'"' -f2
anubhava
źródło
2
Lub krócej:cut -d\" -f2
@AndersJohansson: Dzięki, dodałem również polecenie cięcia, aby odpowiedzieć.
anubhava
Myślę, że to nie zadziała ... widać, że numer pola ścieżki do pliku nie został naprawiony 2 USD lub F2 .. Dzięki!
W rzeczywistości rsync zawsze zapisuje najpierw ścieżkę do pliku pomiędzy "i "na stderr.
anubhava,
1
@ Jam88: Właściwie to zadziała ze względu na sposób, w jaki napisał to Anubbhava. Separator pola jest ustawiony na podwójny cudzysłów. Oznacza to, że wszystko do pierwszego podwójnego cudzysłowu (być może pustego ciągu) jest $1; wszystko między pierwszym a drugim podwójnym cudzysłowem jest $2; i wszystko po drugim podwójnym cytacie jest w $3( $4, ...). Nazwa pliku jest (najwyraźniej) zawsze pomiędzy dwoma pierwszymi podwójnymi cudzysłowami, więc to rozwiązanie powinno działać (i działało, kiedy go testowałem).
Jonathan Leffler,
6

Używanie sed:

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

To szuka: początku linii, szeregu niekwotowań, podwójnego cytatu, przechwytuje szereg niekwotowań, podwójnego cytatu i wszystkiego innego w linii i zastępuje go przechwyconym materiałem.

$ 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
$

Przetestuj na RHEL 5 Linux z GNU sed, ale tylko przy użyciu funkcji, które działałyby w 7. edycji UNIX ™ sed.

Nawiasem mówiąc, nieco prostszym sposobem na to jest użycie dwóch poleceń zastępczych; zmień wszystko do pierwszego podwójnego cudzysłowu włącznie z pustym ciągiem (jest to sekwencja zero lub więcej niekwotowań, po których następuje podwójny cudzysłów); zmień wszystko po tym, co jest teraz pierwszym podwójnym cytatem na nic:

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

Nawiasem mówiąc, wypróbowane polecenie (`sed -n '/" /, / "/ p') drukuje od jednego wiersza zawierającego podwójny cudzysłów do następnego wiersza zawierającego podwójny cudzysłów, bez edytowania wierszy. Dlatego wydawało się, że to nie działa dla ciebie - zrobiło to, o co prosiłeś, ale to, o co prosiłeś, nie było tym, o co chciałeś poprosić.

Jeśli chodzi o efektywność, nie będzie prawdopodobnie mierzalnej różnicy w wydajności. Pod względem łatwości konserwacji podejrzewam, że ta ostatnia jest mniej obciążająca komórki mózgowe.

Jonathan Leffler
źródło
1

Jeśli Twoja wersja grepobsługuje Perl-regexp:

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

Wyniki:

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

Możesz także uczynić to mniej surowym, aby dopasować cokolwiek między podwójnymi, jeśli chcesz:

grep -oP '(?<=")[^"]*' file >> anotherfile
Steve
źródło
Czy musisz zrobić z .*niechęci, .*?na wypadek, gdyby w dalszej kolejności pojawiła się dodatkowa podwójna wycena? Lub użyj [^"]*zamiast .*?
Jonathan Leffler,
-1

Użyj operatora >>, aby zapisać dane wyjściowe w pliku.

Lubić

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

Więc po prostu zmień to w swoim konkretnym scenariuszu, używając sed, dołączając

>> filename

do polecenia

AStupidNoob
źródło
grep -rRobi rekurencyjne przeszukiwanie za pośrednictwem dowolnego katalogach wymienionych w argumentach ( *). Nie jest jasne, jaki wzór masz na myśli, ale grepprzejmie całą linię. Celem ćwiczenia jest zebranie informacji z części linii. Jeśli używasz GNU grep, są na to sposoby ( -o); są to niestandardowe (z wyjątkiem zakresu, w którym GNU definiuje de facto standard). Podobnie z użyciem wyrażeń regularnych PCRE; są to kolejne rozszerzenia GNU. Są w porządku, jeśli masz GNU grepi nie planujesz pracy na platformach, na których GNU grepnie jest domyślnie dostępne.
Jonathan Leffler,
Przepraszam, że tego nie zauważyłem, myślałem, że chciał wiedzieć, co zrobić, aby umieścić dane wyjściowe w pliku, a grep był tylko przykładem.