Jak mogę wykonać dwa polecenia na jednym wejściu, nie wpisując tego dwukrotnie?
Na przykład polecenie stat wiele mówi o pliku, ale nie wskazuje jego typu:
stat fileName
Polecenie file określa typ pliku:
file fileName
Możesz to zrobić w jednym wierszu w ten sposób:
stat fileName ; file fileName
Musisz jednak wpisać fileName dwa razy.
Jak możesz wykonać oba polecenia na tym samym wejściu (bez dwukrotnego wpisywania wejścia lub zmiennej wejścia)?
W systemie Linux wiem, jak przesyłać dane wyjściowe, ale jak przesyłać dane wejściowe?
command-line
Lonniebiz
źródło
źródło
<
(dane wejściowe z pliku do lewej strony) lub|
(dane wejściowe ze strumienia do prawej strony). Jest różnica.yank-last-arg
komenda (domyślny skrótMeta-.
lubMeta-_
;Meta
często jest lewyAlt
klawisz) spowoduje skopiowanie ostatniego parametru z poprzedniego wiersza poleceń do obecnego. Tak więc, po wykonaniustat fileName
wpiszeszfile [Meta-.]
i nie trzeba wpisywać, żefileName
ponownie. Zawsze tego używam.<
i>
są przekierowania , nie potokiem . Potok łączy dwa procesy, a przekierowanie po prostu ponownie przypisuje stdin / stdout.Odpowiedzi:
Oto inny sposób:
Przykład:
To działa w
bash
izsh
. Działa to również w trybie interaktywnymmksh
idash
tylko wtedy. W AT&T ksh działa to tylko wtedy, gdyfile "$_"
znajduje się w innym wierszu niż tenstat
.źródło
!$
Jeden nie zadziała, ponieważ!$
rozszerza się do ostatniego słowa ostatniego zdarzenia historii (jak poprzednio wprowadzonej linii poleceń, a nie polecenia stat).Prawdopodobnie doprowadzę do tego, że moje kostki zostaną w tym celu zastrzelone, oto hacky zestaw ekspansji nawiasów klamrowych i ewaluacji, który wydaje się załatwić sprawę
źródło
csh
, a niebash
.bash
skopiowałem to zksh
. Ten kod będzie działał we wszystkich csh, tcsh, ksh, zsh, fish i bash.eval
? (odnosząc się do najlepszych komentarzy)Za pomocą
zsh
możesz korzystać z anonimowych funkcji:Z
es
lambdami:Możesz także:
(wykonanie
stat
pierwszego jakofile
spowoduje aktualizację czasu dostępu).Mogłabym zrobić:
jednak po to są zmienne.
źródło
{ stat -; file -;} < filename
jest magia.stat
musi sprawdzać, czy jego standardowe wejście jest połączone z plikiem i zgłaszać atrybuty pliku? Prawdopodobnie nie przesuwa wskaźnika na stdin, dlatego pozwalafile
wąchać zawartość stdinstat -
każestat
zrobićfstat()
na swoim fd 0.{ $COMMAND_A -; $COMMAND_B; } < filename
Wariant nie będzie działać w ogólnym przypadku, jeśli $ COMMAND_A faktycznie czyta żadnych danych; np.{ cat -; cat -; } < filename
wydrukuje zawartość nazwy pliku tylko raz.stat -
jest obsługiwany specjalnie od coreutils-8.0 (październik 2009), w wersjach wcześniejszych pojawi się błąd (chyba że masz plik wywołany-
z poprzedniego eksperymentu, w którym to przypadku otrzymasz nieprawidłowe wyniki ...)stat -f0
zamiast tego.Wszystkie te odpowiedzi wydają mi się w mniejszym lub większym stopniu skryptem. Aby uzyskać rozwiązanie, które naprawdę nie wymaga pisania skryptów i zakłada, że siedzisz przy klawiaturze, pisząc w powłoce, możesz spróbować:
Przynajmniej w bash, zsh i ksh, zarówno w trybach vi, jak i emacs, naciśnięcie Escape, a następnie podkreślenie wstawia ostatnie słowo z poprzedniego wiersza do bufora edycji bieżącego wiersza.
Lub możesz użyć podstawienia historii:
W powłokach bash, zsh, csh, tcsh i większości innych
!$
jest zastępowany ostatnim słowem poprzedniego wiersza poleceń, gdy bieżący wiersz poleceń jest analizowany.źródło
Esc _
? Czy możesz połączyć się z oficjalną dokumentacją?Sposób, w jaki znalazłem to rozsądnie, polega na użyciu xargs, bierze plik / potok i konwertuje jego zawartość na argumenty programu. Można to połączyć z trójnikiem, który dzieli strumień i wysyła go do dwóch lub więcej programów. W twoim przypadku potrzebujesz:
W przeciwieństwie do wielu innych odpowiedzi, zadziała to w bash i większości innych powłok pod Linuksem. Zasugeruję, że jest to dobry przypadek użycia zmiennej, ale jeśli absolutnie nie możesz jej użyć, jest to najlepszy sposób, aby to zrobić tylko za pomocą potoków i prostych narzędzi (zakładając, że nie masz szczególnie wymyślnej powłoki).
Dodatkowo możesz to zrobić dla dowolnej liczby programów, po prostu dodając je w taki sam sposób, jak te dwa po tee.
EDYTOWAĆ
Jak sugerowano w komentarzach, w tej odpowiedzi jest kilka wad, pierwszą z nich jest potencjał przeplatania wyników. Można to naprawić w następujący sposób:
Zmusi to kolejno polecenia do działania, a dane wyjściowe nigdy nie będą miały przeplotu.
Drugim problemem jest unikanie podstawiania procesów, które nie jest dostępne w niektórych powłokach, można to osiągnąć za pomocą tpipe zamiast tee, ponieważ:
Powinien być przenośny na prawie każdą powłokę (mam nadzieję) i rozwiązuje problemy w innym poleceniu, jednak piszę ten ostatni z pamięci, ponieważ mój obecny system nie ma dostępnego tpipe.
źródło
ksh
(nie w wariantach domeny publicznej)bash
izsh
. Zauważ, żestat
ifile
będą działać jednocześnie, więc być może ich dane wyjściowe zostaną splecione (przypuszczam, że używasz| cat
wymuszania buforowania danych wyjściowych w celu ograniczenia tego efektu?).Ta odpowiedź jest podobna do kilku innych:
W przeciwieństwie do innych odpowiedzi, które automatycznie powtarzają ostatni argument z poprzedniego polecenia, ta wymaga policzenia:
W przeciwieństwie do niektórych innych odpowiedzi, nie wymaga to cytowania:
lub
źródło
Jest to podobne do kilku innych odpowiedzi, ale jest bardziej przenośne niż ta i znacznie prostsze niż ta :
lub
w którym
sh
jest przypisany do$0
. Chociaż do wpisania są trzy znaki, ta (druga) forma jest lepsza, ponieważ$0
taką nazwę nadajesz temu wbudowanemu skryptowi. Jest używany na przykład w komunikatach o błędach przez powłokę dla tego scenariusza, jak wtedy, gdyfile
albostat
nie można znaleźć lub nie może być wykonany z dowolnego powodu.Jeśli chcesz to zrobić
dla dowolnej liczby plików, wykonaj
który działa, ponieważ
"$@"
jest równoważny z"$1" "$2" "$3" …
.źródło
$0
jest nazwa, którą chcesz nadać temu wbudowanemu skryptowi. Jest używany na przykład w komunikatach o błędach przez powłokę dla tego skryptu. Jak wtedy, gdyfile
albostat
nie można znaleźć lub nie może być wykonany z dowolnego powodu. Chcesz tutaj czegoś sensownego. Jeśli nie jesteś zainspirowany, po prostu użyjsh
.Myślę, że zadajesz złe pytanie, przynajmniej za to, co próbujesz zrobić.
stat
afile
polecenia przyjmują parametry, które są nazwą pliku, a nie jego zawartością. Jest to później polecenie, które odczytuje plik identyfikowany przez podaną nazwę.Rura ma mieć dwa końce, jeden używany jako dane wejściowe, a drugi jako dane wyjściowe, co ma sens, ponieważ może być konieczne wykonanie różnych operacji po drodze przy użyciu różnych narzędzi, aż do uzyskania pożądanego rezultatu. Mówienie, że wiesz, jak przesyłać dane wyjściowe, ale nie wiesz, jak przesyłać dane wejściowe, jest w zasadzie niepoprawne.
W twoim przypadku wcale nie potrzebujesz potoku, ponieważ musisz podać dane wejściowe w postaci nazwy pliku. I nawet jeśli te narzędzia (
stat
ifile
) odczytałyby standardowe wejście, potok nie ma tu znaczenia, ponieważ dane wejściowe nie powinny być zmieniane przez żadne z narzędzi, gdy dojdzie do drugiego.źródło
Powinno to działać dla wszystkich nazw plików w bieżącym katalogu.
źródło
}
znaku wstecznego, ... i nie zaczynaj od-
. Niektóreprintf
implementacje (zsh, bash, ksh93) mają%q
. Zzsh
może to być:printf 'stat %q; file %1$q\n' ./* | zsh
sed
s///
, ale chyba chodzi o zakres - a jeśli ludzie umieszczają to w swoich nazwach plików, powinni używać okien.*
dwa razy . Równie dobrze możesz powiedziećstat -- *; file -- *
.*
jest rozwijane. Rozprężny z*
plus dwa polecenia dla każdej zmiennej w*
to wejściowego. Widzieć?printf commands\ %s\;shift *
Jest tu kilka różnych odniesień do „danych wejściowych”, dlatego przedstawię kilka scenariuszy, mając na uwadze przede wszystkim ich zrozumienie. Aby uzyskać szybką odpowiedź na pytanie w najkrótszej formie :
Powyższe wykona statystyki na pliku testowym, weź (przekieruje) to STDOUT i uwzględni to w następnej funkcji specjalnej (część <()), a następnie wyśle ostateczne wyniki tego, co było, do nowego pliku (plik wyjściowy). Plik jest wywoływany, a następnie odwoływany do wbudowanych bash (1 $ za każdym razem, dopóki nie zaczniesz nowego zestawu instrukcji).
Twoje pytanie jest świetne i istnieje kilka odpowiedzi i sposobów na zrobienie tego, ale tak naprawdę zmienia się w zależności od tego, co robisz.
Na przykład możesz to również zapętlić, co jest dość przydatne. Typowym zastosowaniem tego jest w myśleniu psuedo-code:
Biorąc to i poszerzając tę wiedzę, możesz tworzyć takie rzeczy jak:
Spowoduje to wykonanie prostej operacji ls -A w bieżącym katalogu, a następnie przekazanie instrukcji pętli do każdego wyniku od ls -A do (i tutaj jest to trudne!) Grep "to słowo" w każdym z tych wyników i wykonanie tylko poprzedniego printf (na czerwono), jeśli rzeczywiście znalazł plik z „tym słowem”. Loguje również wyniki grep do nowego pliku tekstowego files_that_matched_thatword.
Przykładowe dane wyjściowe:
Wszystko to po prostu wydrukowało wynik ls-A, nic specjalnego. Dodaj coś, aby tym razem grep:
Teraz uruchom ponownie:
Chociaż być może jest to bardziej wyczerpująca odpowiedź, niż szukasz obecnie, uważam, że trzymanie takich przydatnych notatek przyniesie ci więcej korzyści w przyszłych przedsięwzięciach.
źródło