Polecenie kota i echo

14

Chciałbym połączyć dane wyjściowe z echa z zawartością pliku. Próbowałem następującego polecenia:

echo "abc" | cat 1.txt > 2.txt

ale 2.txtplik zawiera tylko treść z 1.txt. Dlaczego to nie działa?

Ringger81
źródło
3
Programy takie jak cattylko czytają ze standardowego wejścia, jeśli nie mają żadnych argumentów nazw plików.
Barmar

Odpowiedzi:

23

To nie działa, ponieważ catprogram w sekwencji potoku nie otrzymał polecenia odczytu danych echowyjściowych programu ze standardowego wejścia.

Możesz użyć -jako pseudo nazwy pliku, aby wskazać standardowe wejście cat. Z man catinstalacji msys2:

EXAMPLES
       cat f - g
              Output f's contents, then standard input, then g's contents.

Więc spróbuj

echo "abc" | cat - 1.txt > 2.txt

zamiast.

mvw
źródło
21

Jak zauważają inni, oryginalne polecenie nie działa, ponieważ nie cat 1.txtuwzględnia standardowych danych wejściowych. Albo wskaż, że powinien być to pierwszy argument ( cat - 1.txt), albo użyj przekierowania blokowego, aby przekierować echo abc i cat 1.txt razem. To znaczy:

{ echo abc; cat 1.txt; } > 2.txt 

Odpowiedni fragment instrukcji ( man bash):

Polecenia złożone Polecenie
złożone to jedno z poniższych. W większości przypadków lista w opisie polecenia może być oddzielona od reszty polecenia jednym lub kilkoma znakami nowej linii, a po nim może być nowy wiersz zamiast średnika.

(lista)

    lista jest wykonywana w środowisku podpowłoki (patrz ŚRODOWISKO WYKONYWANIA POLECEŃ poniżej). Zmienne przypisania i wbudowane polecenia, które wpływają na środowisko powłoki, nie pozostają aktywne po zakończeniu polecenia. Status powrotu to status wyjścia z listy.

{lista; }

    lista jest po prostu wykonywana w bieżącym środowisku powłoki.  lista musi być zakończona znakiem nowej linii lub średnikiem. Jest to znane jako polecenie grupowe . Status powrotu to status wyjścia z listy . Należy zauważyć, że w przeciwieństwie do metaznaków (i ), {i }zarezerwowane słowa i musi występować gdzie słowo zarezerwowane jest dozwolone być uznawane. Ponieważ nie powodują podziału słów, muszą być oddzielone od listy spacją lub innym metaznakiem powłoki.

Pierwsza opcja (środowisko podpowłoki) ma wiele efektów ubocznych, z których większość, jeśli nie wszystkie, są nieistotne dla twojego scenariusza; jeśli jednak przekierowanie zestawu poleceń jest wystarczające, preferowana jest opcja 2 tutaj (polecenie grupowe).

Nubarke
źródło
7
( echo "abc"; cat 1.txt ) > 2.txt

Przekazałeś wyjście echa do cat, ale cat nie używał danych wejściowych i zignorowałeś je. Teraz polecenia są uruchamiane jeden po drugim, a ich dane wyjściowe są grupowane (w nawiasach) i kierowane do 2.txt.

Gerard H. Pille
źródło
1
Odpowiedź można poprawić, wyjaśniając, jak to działa i dlaczego pierwotna próba PO nie działa.
Bob
OK, spróbowałem.
Gerard H. Pille,
5
Nie jest tu wyraźnie wymagana podpowłoka, być może lepiej byłoby użyć polecenia grupy. Zobacz moją odpowiedź, aby uzyskać więcej informacji.
Nubarke
Ach, ale nigdy nie użyłbym bash.
Gerard H. Pille,
1
@ GerardH.Pille: Chociaż odpowiedź Daniela cytuje bash(1), opisuje zachowanie, które musi obsługiwać każda powłoka zgodna z POSIX .
G-Man mówi „Przywróć Monikę”
2

Twoje polecenie cat 1.txtnic nie robi z wyjściem echo "abc".

Zamiast tego: (echo "abc"; cat 1.txt) > 2.txt zapisze dane wyjściowe obu poleceń w 2.txt.

śluz
źródło
Odpowiedź można poprawić, wyjaśniając, jak działa sugerowana alternatywa.
Bob
1

W dowolnej powłoce POSIX można użyć podstawiania poleceń, aby użyć cat filejako danych wejściowych dla echo:

echo $(cat file1.txt) "This Too"

W Bash możesz użyć podstawienia procesu i użyć echa jako innego „pliku” dla cat, jak w:

cat file1.txt <(echo This Too)

a następnie potokuj lub przekieruj wyjście według własnego uznania.

Jak każda inna odpowiedź mówi, cat ignoruje stdin, jeśli ma plik do obejrzenia. (Lubię też odpowiedzi Daniela i mvw, +1 za nich)

Xen2050
źródło
1
Odpowiedź można poprawić, wyjaśniając, dlaczego pierwotna próba PO nie działa (a zatem dlaczego jest to konieczne).
Bob
1
<(command)Konstrukcja jest rozszerzeniem bash. To nie jest POSIX, więc nie można na nim polegać w skryptach, które powinny być wykonywane /bin/sh.
Rhialto obsługuje Monikę
0

Tylko zgadnij, ale wygląda na to, że masz powtarzalny proces, który jest dobrym kandydatem na alias lub funkcję. Aliasy są zwykle skrótami do wywoływania poleceń bash, takich jak skrót, w jednym strumieniu wejściowym jako argumentach.

alias hg="history | grep"

Jednak w tym przypadku funkcja byłaby bardziej czytelna, ponieważ łączysz wiele dyskretnych (2) strumieni wejściowych, a także wiele poleceń bash. Masz dwa argumenty, pierwszy to ciąg, a drugi ścieżka do pliku. Na koniec chcesz, aby wynik został zapisany w standardowym strumieniu wyjściowym.

W wierszu polecenia CLI wpisz:

# ecat()        
{
echo ${1}
cat ${2}
}

Twoja funkcja nosi nazwę ecat, co zapada w pamięć.

Teraz możesz wywołać jako

ecat "abc" 1.txt

Aby dołączyć, po prostu podaj inne miejsce docelowe wyjścia na standardowe wyjście:

ecat "abc" 1.txt >> 2.txt

Dołącz przekierowanie „>>” doda dane wyjściowe na końcu określonego pliku.

Jeśli Ci się spodoba, dołącz do pliku ~ / .bashrc w celu ponownego użycia.

declare -f ecat >> ~/.bashrc

Oznacza to również, że możesz dekorować itp. W ramach definicji funkcji.

Warto też zabezpieczyć pliki przed nadpisaniem, dodając to do ~ / .bashrc

set noclobber
FrDarryl
źródło
2
Aby funkcja działała poprawnie, należy użyć "$1"i "$2". W tym kontekście nawiasy klamrowe nie przynoszą nic dobrego. Patrz ${name}, nie oznacza to, co myślisz, że robi ... .
G-Man mówi „Przywróć Monikę”
1
W jaki sposób noclobbersugestia odpowiada na dane pytanie? (Jestem również bardzo nieprzekonany, że to dobra rada - modyfikowanie globalnych zachowań ma tendencję do łamania skryptów / porad / praktyk zbudowanych z myślą o domyślnych ustawieniach).
Charles Duffy
0

Działa również następujący kod:

echo abc >> 1.txt && cat 1.txt > 2.txt

Wyjście echo abc zostanie dołączone do 1.txt za pomocą >> Po tym && powie mu, aby uruchomił następny zestaw poleceń, który wykona cat 1.txt, a następnie wyśle go do 2.txt . Zasadniczo dołącza wynik pierwszego polecenia do 1.txt, a następnie wysyła wynik 1.txt do 2.txt.

Jeśli chcesz, aby abc pojawiał się jako pierwszy, możesz użyć następującego kodu:

echo abc >> 2.txt && cat 1.txt >> 2.txt
Nasir Riley
źródło
1
Będzie to (1) umieścić abcna dnie w 2.txt; pytanie chce na górze. (2)  modyfikację w 1.txtpliku; to jest niedopuszczalne.
G-Man mówi „Reinstate Monica”
Gdzie to mówi? Ringger81 nigdy nie określił, gdzie w 2.txt ma pojawić się abc. Zakładasz rzeczy, których pytanie nigdy nie mówi.
Nasir Riley
(1) OK, podnosisz ważny punkt na # 1. Podczas gdy pytanie wspomina o „danych wyjściowych z echa” przed „zawartością pliku” w tekście, a następnie umieszcza echoprzed catpoleceniem przykładowym, przypuszczam, że nigdy dokładnie nie mówi wprost , że chce danych wyjściowych z echa przed zawartość pliku wejściowego. Wydaje się, że większość ludzi tak to interpretowała. (2)  1.txtto plik wejściowy. Pytanie nie mówi nic o modyfikacji 1.txt. Fakt, że pliki wejściowe nie powinny być modyfikowane, jest oczywisty.
G-Man mówi „Przywróć Monikę”
Rozumiem twój punkt widzenia, że ​​nie modyfikujesz pliku imput. Mój drugi kod osiągnie pożądany efekt bez robienia tego.
Nasir Riley
1
Otwieranie pliku, dołączanie do niego, zamykanie go , otwieranie go ponownie, dołączanie do niego ponownie ... dlaczego to zrobić, zamiast tylko raz otworzyć i zachować przekierowanie dla obu operacji?
Charles Duffy