Mam dwa równoległe pliki z taką samą liczbą wierszy w dwóch językach i planuję połączyć te dwa pliki linia po linii z separatorem |||
. Np. Dwa pliki są następujące:
Plik a:
1Mo 1,1 I love you.
1Mo 1,2 I like you.
Hi 1,3 I am hungry.
Hi 1,4 I am foolish.
Plik B:
1Mo 1,1 Ich liebe dich.
1Mo 1,2 Ich mag dich.
Hi 1,3 Ich habe Durst.
Hi 1,4 Ich bin neu.
Oczekiwany wynik jest następujący:
1Mo 1,1 I love you. ||| 1Mo 1,1 Ich liebe dich.
1Mo 1,2 I like you. ||| 1Mo 1,2 Ich mag dich.
Hi 1,3 I am hungry. ||| Hi 1,3 Ich habe Durst.
Hi 1,4 I am foolish. ||| Hi 1,4 Ich bin neu.
Próbowałem paste
polecenia, takiego jak:
paste -d "|||" fileA fileB
Ale zwracane dane wyjściowe zawierają tylko jedną potok, na przykład:
1Mo 1,1 I love you. |1Mo 1,1 Ich liebe dich.
1Mo 1,2 I like you. |1Mo 1,2 Ich mag dich.
Czy jest jakiś sposób na oddzielenie każdej pary linii za pomocą trójnogu |||
?
text-processing
sed
awk
Marszczyć brwi
źródło
źródło
paste -d '|||' fileA - - fileB < /dev/null
Odpowiedzi:
Z pastą POSIX :
paste
połączy odpowiednie linie wszystkich plików wejściowych. Tutaj mamy sześć plików,fileA
cztery atrapy plików ze standardowych w-
ifileB
.Lista ograniczników obejmuje spację, trzy potoki i spację w tej kolejności będą używane
paste
cyklicznie.Dla pierwszego wiersza sześciu plików
fileA
zostanie połączony z pierwszym plikiem zastępczym (który jest niczym, dzięki operatorowi no-op :), produkujeline1-fileA<space>
.Pierwszy plik fikcyjny zostanie połączony z drugim przez potok, produkuj
line1-fileA |
, a następnie drugi plik fikcyjny z trzecim plikiem fikcyjnym, produkujline1-fileA ||
, trzeci plik fikcyjny z czwartym plikiem fikcyjnym, produkujline1-fileA |||
.A czwarty plik atrapa z
fileB
, produkujline1-fileA ||| line1-fileB
.Te kroki zostaną powtórzone dla wszystkich linii, dając oczekiwany wynik.
Użycie
:|
jest do pisania na maszynie mniej i głównie w interaktywnej powłoce. W skrypcie należy użyć:aby zapobiec spawnowaniu podpowłoki.
źródło
:|
. sprytna alternatywa dla</dev/null
- - - -
, ale następnym razem możesz nawet napisać kilka wierszy dla wyjaśnienia :):|paste -d '|' fileA - - fileB
daje bardziej poprawną wersję bez separatora spacji.Cóż, to nie używa sed, awk ani grep, ale możesz to zrobić dość łatwo w bash. Polecenie to:
Problem z wklejaniem polega na tym, że separator jest pojedynczym znakiem. Możesz także wstawić pojedynczy znak i użyć sed, aby go przekształcić, ale byłoby to podatne na błędy, jeśli znak już pojawił się w pliku wejściowym.
źródło
IFS=
przed każdymread
. Możesz łatwo to zrobićpaste
. Zobacz moją odpowiedź , a także tę, aby dowiedzieć się, dlaczego warto unikać używaniawhile
pętli w skrypcie powłoki.Wersja awk (GNU)
Za pomocą
getline
polecenia wawk
możesz ustawić$0
(wszystkie zmienne dla kolumn) z następnego rekordu wejściowego, jeśligetline < "filename"
ustawisz następny$0
z określonego pliku.Dlaczego Twoja próba nie zadziałała zgodnie z oczekiwaniami? Z
man paste
możemy przeczytaćale używa ograniczników po jednym dla każdej kolumny .
Więc polecenie
paste -d '|*|*' fileA fileB fileA fileB
podaje mi linie jakosed
Rozwiązanie, które proponuję, aby uniknąć nawet jeśli blisko do oryginalnej próbie, gdyż łata uzyskany zachowania do swojego pierwotnego celu:Aby tego uniknąć, ponieważ zastępujesz każdy wzorzec
|
nowym|||
, ale musisz założyć, że symbol potoku (|
) nie jest obecny w twoich danych , w przeciwnym razie musisz poradzić sobie ze specjalnymi przypadkami i uczynić kod bardziej złożonym, aby uniknąć skutków ubocznych.Wariant z konstrukcją Here String [ 1 ]
<<<
Ustawiasz 5 ograniczników za pomocą
-d ' ||| '
(spacja, |, |, |, spacja) i 4 plików zastępczych (- - - -
), które będą pobierać dane z pustego ciągu''
.Testowane na GNU Awk 4.0.1, wklej (GNU coreutils) 8.21 i sed (GNU sed) 4.2.2
źródło
sed
przykład, aby uniknąć (:-)) i więcej komentarzy.Jeśli chcesz uniknąć magii i dramaturgii okrągłych separatorów i plików zastępczych, możesz po prostu dołączyć separator do jednego pliku przed ich wklejeniem:
daje
źródło
możesz to zrobić w Pythonie również w ten sposób.
źródło