Poniższy skrypt Perla ( my.pl
) może czytać z pliku w args wiersza poleceń lub ze STDIN:
while (<>) {
print($_);
}
perl my.pl
odczyta ze STDIN, a perl my.pl a.txt
odczyta z a.txt
. To jest bardzo wygodne.
Zastanawiasz się, czy w Bash istnieje odpowiednik?
/proc/$$/fd/0
a/dev/stdin
? Zauważyłem, że ten drugi wydaje się bardziej powszechny i wygląda na bardziej prosty.-r
do swojejread
komendy, aby przypadkowo nie zjadła\
znaków; służywhile IFS= read -r line
do zachowania wiodących i końcowych białych znaków./bin/sh
- czy używasz powłoki innej niżbash
lubsh
?Być może najprostszym rozwiązaniem jest przekierowanie stdin za pomocą łączącego operatora przekierowania:
Stdin to zero deskryptorów plików. Powyższe powoduje przesłanie danych wejściowych do skryptu bash do standardowego interfejsu less.
Dowiedz się więcej o przekierowaniu deskryptora pliku .
źródło
<&0
tej sytuacji nie ma żadnej korzyści - twój przykład będzie działał tak samo z nią, jak i bez niej - najwyraźniej narzędzia, które wywołujesz z poziomu skryptu bash, domyślnie widzą to samo stdin co sam skrypt (chyba że skrypt zużyje go jako pierwszy).Oto najprostszy sposób:
Stosowanie:
Aby przypisać stdin do zmiennej, możesz użyć:
STDIN=$(cat -)
lub po prostu,STDIN=$(cat)
ponieważ operator nie jest konieczny (zgodnie z komentarzem @ mklement0 ).Aby przeanalizować każdy wiersz ze standardowego wejścia , wypróbuj następujący skrypt:
Aby odczytać z pliku lub standardowego wejścia (jeśli nie ma argumentu), możesz go rozszerzyć do:
Zobacz: Jak czytać stdin, gdy nie są przekazywane żadne argumenty? w stackoverflow SE
źródło
[ "$1" ] && FILE=$1 || FILE="-"
doFILE=${1:--}
. (Quibble: lepiej unikać zmiennych wielkimi literami w powłoce , aby uniknąć kolizji nazw ze zmiennymi środowiskowymi .)${1:--}
jest zgodny z POSIX, więc powinien działać we wszystkich powłokach podobnych do POSIX. To, co nie zadziała we wszystkich takich powłokach, to proces substytucji (<(...)
); będzie działał na przykład w bash, ksh, zsh, ale nie w desce rozdzielczej. Lepiej też dodać-r
do swojegoread
polecenia, aby przypadkowo nie zjadł\
znaków; starająIFS=
się zachować wiodące i końcowe białe znaki.echo
: jeśli linia składa się z-e
,-n
lub-E
, nie będą wyświetlane. Aby rozwiązać ten problem, należy użyćprintf
:printf '%s\n' "$line"
. Nie uwzględniłem go w mojej poprzedniej edycji… zbyt często moje zmiany są wycofywane, gdy naprawiam ten błąd:(
.--
jest bezużyteczne, jeśli pierwszy argument to'%s\n'
IFS=
zread
iprintf
zamiastecho
.:)
.Myślę, że jest to prosty sposób:
-
-
źródło
read
czyta z stdin domyślnie , więc nie ma potrzeby na< /dev/stdin
.echo
Rozwiązanie dodaje nowe linie gdyIFS
przełamuje strumień wejściowy. Odpowiedź @ fgm można nieco zmodyfikować:źródło
read
„s zachowanie: gdyread
ma potencjalnie podzielone na wiele żetonów przez znaki. zawarty w$IFS
nim, zwraca tylko jeden token, jeśli podasz tylko jedną nazwę zmiennej (ale domyślnie przycina i początkowe i końcowe białe znaki).read
i$IFS
-echo
sama dodaje nowe linie bez-n
flagi. „Narzędzie echo zapisuje na standardowym wyjściu dowolne określone operandy, oddzielone pojedynczymi pustymi znakami (` `), a następnie znakiem nowej linii (` \ n '). ”\n
dodać znak końcowyecho
: Perl$_
zawiera linię kończącą się\n
na czytanej linii, podczas gdy bashread
nie. (Jednak, jak wskazuje @gniourf_gniourf w innym miejscu, bardziej niezawodne podejście można zastosowaćprintf '%s\n'
zamiastecho
).Pętla Perla w pytaniu czyta wszystkie argumenty nazwy pliku w wierszu poleceń lub ze standardowego wejścia, jeśli nie określono żadnych plików. Wszystkie odpowiedzi, które widzę, wydają się przetwarzać pojedynczy plik lub standardowe dane wejściowe, jeśli nie określono pliku.
Chociaż często wyśmiewane jako UUOC (Bezużyteczne użycie
cat
), zdarzają się chwile, kiedycat
jest to najlepsze narzędzie do pracy i można argumentować, że jest to jedno z nich:Jedynym minusem jest to, że tworzy potok działający w podpowłoce, więc rzeczy takie jak przypisania zmiennych w
while
pętli nie są dostępne poza potokiem. Rozwiązaniembash
tego problemu jest proces zastępowania :To powoduje, że
while
pętla działa w głównej powłoce, więc zmienne ustawione w pętli są dostępne poza nią.źródło
>>EOF\n$(cat "$@")\nEOF
. Wreszcie, spór:while IFS= read -r line
jest lepszym przybliżeniem tego, cowhile (<>)
robi w Perlu (zachowuje wiodące i końcowe białe spacje - chociaż Perl również utrzymuje końcowe\n
).Zachowanie Perla, z kodem podanym w OP, nie może przyjmować żadnego lub kilku argumentów, a jeśli argument jest pojedynczym łącznikiem,
-
jest to rozumiane jako standardowe. Co więcej, zawsze można mieć nazwę pliku$ARGV
. Żadna z podanych do tej pory odpowiedzi nie naśladuje zachowania Perla pod tym względem. Oto czysta możliwość Bash. Sztuka polega naexec
odpowiednim użyciu .Nazwa pliku jest dostępna w
$1
.Jeśli nie podano żadnych argumentów, sztucznie ustawiamy
-
jako pierwszy parametr pozycyjny. Następnie zapętlamy parametry. Jeśli parametr nie jest-
, przekierowujemy standardowe wejście z nazwy pliku za pomocąexec
. Jeśli przekierowanie się powiedzie, zapętlamywhile
pętlę. UżywamREPLY
zmiennej standardowej , w tym przypadku nie trzeba resetowaćIFS
. Jeśli chcesz mieć inną nazwę, musiszIFS
tak zresetować (chyba że oczywiście nie chcesz tego i wiesz, co robisz):źródło
Dokładniej...
źródło
IFS=
i-r
doread
polecenia zapewnia, że każdy wiersz jest odczytywany w niezmodyfikowany sposób (w tym początkowe i końcowe białe znaki).Wypróbuj następujący kod:
źródło
read
bezIFS=
i-r
, i biednego$line
bez jego zdrowych cytatów.read -r
notacja. IMO, POSIX źle to zrozumiał; opcja powinna włączyć specjalne znaczenie dla końcowych ukośników odwrotnych, a nie wyłączyć je - aby istniejące skrypty (sprzed istnienia POSIX-a) nie uległy awarii, ponieważ-r
zostały pominięte. Zauważam jednak, że był on częścią IEEE 1003.2 1992, który był najwcześniejszą wersją standardu powłoki i narzędzi POSIX, ale już wtedy został oznaczony jako dodatek, więc to dziwne o dawno minionych szansach. Nigdy nie miałem problemów, ponieważ mój kod nie używa-r
; Muszę mieć szczęście. Zignoruj mnie w tej sprawie.-r
powinien być standardem. Zgadzam się, że jest to mało prawdopodobne w przypadkach, gdy nieużywanie go prowadzi do problemów. Chociaż uszkodzony kod jest uszkodzony. Moja edycja została po raz pierwszy uruchomiona przez tę kiepską$line
zmienną, która bardzo pominęła swoje cytaty. Naprawiłemread
czas, w którym tam byłem. Nie naprawiłem tego,echo
ponieważ taka zmiana jest wycofywana.:(
.Kod
${1:-/dev/stdin}
po prostu zrozumie pierwszy argument, więc co powiesz na to.źródło
Żadna z tych odpowiedzi nie jest do przyjęcia. W szczególności zaakceptowana odpowiedź obsługuje tylko pierwszy parametr wiersza poleceń i ignoruje resztę. Program Perla, który próbuje emulować, obsługuje wszystkie parametry wiersza poleceń. Tak więc zaakceptowana odpowiedź nawet nie odpowiada na pytanie. Inne odpowiedzi używają rozszerzeń bash, dodają niepotrzebne polecenia „cat”, działają tylko w prostym przypadku echa wejścia do wyjścia lub są po prostu niepotrzebnie skomplikowane.
Muszę jednak podziękować im, ponieważ dali mi pomysły. Oto pełna odpowiedź:
źródło
Połączyłem wszystkie powyższe odpowiedzi i stworzyłem funkcję powłoki, która odpowiada moim potrzebom. To pochodzi z terminalu cygwin na moich 2 komputerach z systemem Windows10, gdzie miałem między nimi folder współdzielony. Muszę być w stanie poradzić sobie z następującymi kwestiami:
cat file.cpp | tx
tx < file.cpp
tx file.cpp
Jeśli określona nazwa pliku jest określona, muszę użyć tej samej nazwy pliku podczas kopiowania. Tam, gdzie strumień danych wejściowych został potokowany, muszę wygenerować tymczasową nazwę pliku mającą godzinę, minutę i sekundy. Udostępniony główny folder ma podfoldery dni tygodnia. To jest do celów organizacyjnych.
Oto najlepszy skrypt dla moich potrzeb:
Jeśli jest jakiś sposób na dalszą optymalizację tego, chciałbym wiedzieć.
źródło
Poniższe działa ze standardem
sh
(Testowane zdash
Debianem) i jest dość czytelne, ale to kwestia gustu:Szczegóły: jeśli pierwszy parametr nie jest pusty, to
cat
ten plik, w przeciwnym raziecat
standardowe wejście. Następnie dane wyjściowe całejif
instrukcji są przetwarzane przezcommands_and_transformations
.źródło
cat "${1:--}" | any_command
. Odczytywanie zmiennych do powłoki i ich echo może działać dla małych plików, ale nie skaluje się tak dobrze.[ -n "$1" ]
Mogą być uproszczone[ "$1" ]
.Ten jest łatwy w użyciu na terminalu:
źródło
Co powiesz na
źródło
cat
zostaną umieszczone w wierszu polecenia. Wiersz polecenia ma maksymalny rozmiar. Również to nie będzie czytać wiersz po wierszu, ale słowo po słowie.