Eu sunt încercarea de a obține bash pentru a prelucra datele de la intrarea standard, care devine, prin conducte, dar nu noroc. Ce vreau să spun este că nici una dintre următoarele lucrări:
echo "hello world" | test=($(< /dev/stdin)); echo test=$test
test=
echo "hello world" | read test; echo test=$test
test=
echo "hello world" | test=`cat`; echo test=$test
test=
unde vreau ieșire pentru a fi test=salutare lume
. Am'am încercat să - "" ghilimele `"$test" asta nu't de lucru, fie.
Utilizarea
IFS= read var << EOF
$(foo)
EOF
Ai poate truc citit
în acceptarea dintr-o țeavă de genul asta:
echo "hello world" | { read test; echo test=$test; }
sau chiar scrie o funcție astfel:
read_from_pipe() { read "$@" <&0; }
Dar nu's nici un punct - sarcini variabile nu poate dura! O conductă poate da naștere la o subshell, unde mediul este moștenit prin valoare, nu prin referință. Acesta este motivul pentru "citit" nu't deranjez cu intrare dintr-o țeavă - l's nedefinit.
FYI, http://www.etalabs.net/sh_tricks.html este un puturos de colectare a cruft necesar pentru a lupta împotriva ciudățenii și incompatibilități de bourne scoici, sh.
dacă doriți să citiți într-o mulțime de date și de a lucra pe fiecare linie separat, ai putea folosi ceva de genul asta:
cat myFile | while read x ; do echo $x ; done
dacă doriți să împartă linii în mai multe cuvinte, puteți folosi mai multe variabile în loc de x, astfel:
cat myFile | while read x y ; do echo $y $x ; done
alternativ:
while read x y ; do echo $y $x ; done < myFile
Dar de îndată ce începi să vrei să faci ceva cu adevărat inteligent cu acest fel de lucru're mai bine merge pentru un limbaj de scripting ca perl unde ai putea încerca ceva de genul asta:
perl -ane 'print "$F[0]\n"' < myFile
Nu's destul de curbă de învățare abruptă cu perl (sau cred că oricare dintre aceste limbi) dar'll găsi mult mai ușor pe termen lung, dacă vrei să faci ceva, dar simplu de script-uri. Am'd recomanda Perl carte de Bucate și, desigur, Perl Limbaj de Programare de Larry Wall et al.
Aceasta este o altă opțiune
$ read test < <(echo hello world)
$ echo $test
hello world
a "citi" a câștigat't citit dintr-o țeavă (sau, eventual, rezultatul este pierdut deoarece conducta creează un subshell). Cu toate acestea, puteți utiliza o aici șir în Bash:
$ read a b c <<< $(echo 1 2 3)
$ echo $a $b $c
1 2 3
Dar vezi @chepner's a răspunde pentru informații despre lastpipe`.
Am'm expert în Bash, dar mă întreb de ce acest lucru nu't fost propuse:
stdin=$(cat)
echo "$stdin"
-O linie dovada că funcționează pentru mine:
$ fortune | eval 'stdin=$(cat); echo "$stdin"'
bash
4.2 introduce lastpipe
opțiune, care permite cod pentru a lucra ca scris, prin executarea ultimei comenzi într-o conductă în shell-ul curent, mai degrabă decât un subshell.
shopt -s lastpipe
echo "hello world" | read test; echo test=$test
Prima încercare a fost destul de aproape. Această modificare ar trebui să funcționeze:
echo "hello world" | { test=$(< /dev/stdin); echo "test=$test"; };
și de ieșire este:
test=salut lume
Ai nevoie de aparat dentar după conductei să anexați misiune pentru a testa și de ecou.
Fără bretele, misiunea de a testa (după conductei) este într-o coajă, și ecoul "test=$test" este separat într-o coajă care nu't știu despre tema asta. Ca's de ce ai "test=" la ieșire în loc de "test=salut lume".
Pentru că nu se încadrează pentru ea, aș dori să picătură o notă. Am gasit acest thread, pentru că trebuie să rescrie un vechi sh script pentru a fi compatibil POSIX. Acest lucru înseamnă, practic, să eludeze țeavă/subshell problema introdus de POSIX prin rescrierea codului astfel:
some_command | read a b c
în:
read a b c << EOF
$(some_command)
EOF
Și ca acest cod:
some_command |
while read a b c; do
# something
done
în:
while read a b c; do
# something
done << EOF
$(some_command)
EOF
Dar acesta din urmă nu se comporta la fel pe gol de intrare. Cu vechea notație buclă în timp ce este introdus în gol de intrare, dar în POSIX notație este! Cred că's, datorită newline înainte de EOF, care nu poate fi omis. La POSIX cod care se comportă mai mult ca vechea notație se pare ca acest lucru:
while read a b c; do
case $a in ("") break; esac
# something
done << EOF
$(some_command)
EOF
În cele mai multe cazuri, acest lucru ar trebui să fie destul de bun. Dar, din păcate, acest lucru încă nu se comportă exact ca vechea notație dacă some_command imprimă o linie goală. În vechea notație în timp ce corpul este executat și în POSIX notație ne rupe în fața corpului.
O abordare pentru a rezolva acest lucru ar putea arata astfel:
while read a b c; do
case $a in ("something_guaranteed_not_to_be_printed_by_some_command") break; esac
# something
done << EOF
$(some_command)
echo "something_guaranteed_not_to_be_printed_by_some_command"
EOF
Următorul cod:
echo "hello world" | ( test=($(< /dev/stdin)); echo test=$test )
va lucra, dar se va deschide un alt nou sub-shell după conductei, în cazul în care
echo "hello world" | { test=($(< /dev/stdin)); echo test=$test; }
a câștigat't.
Am avut pentru a dezactiva control de locuri de muncă pentru a face uz de chepnars' metoda (am fost de a rula această comandă din terminal):
set +m;shopt -s lastpipe
echo "hello world" | read test; echo test=$test
echo "hello world" | test="$(</dev/stdin)"; echo test=$test
lastpipe
Dacă este setat, și de locuri de muncă de control nu este activ, shell-ul se execută ultima comandă de o conductă să nu fie executat în fundal în shell-ul curent mediu.
Notă: lucrare de control este dezactivat în mod implicit într-un mod non-interactiv coajă și, astfel, nu't nevoie de set +m` în interiorul unui script.
Cred că ai fost încercarea de a scrie un script shell care ar putea să ia de intrare de la stdin. dar în timp ce sunteți încercarea de a face inline, te-ai pierdut încercarea de a crea acel test= variabilă. Cred că nu prea are sens să-l facă inline, și că's de ce nu funcționează așa cum vă așteptați.
Am fost încercarea de a reduce
$( ... | head -n $X | tail -n 1 )
pentru a obține o anumită linie din diverse intrare. așa am putut de tip...
cat program_file.c | line 34
deci am nevoie de un mic program shell capabil de a citi de la intrarea standard. cum faci tu.
22:14 ~ $ cat ~/bin/line
#!/bin/sh
if [ $# -ne 1 ]; then echo enter a line number to display; exit; fi
cat | head -n $1 | tail -n 1
22:16 ~ $
acolo te duci.
Un script inteligente care pot citi date de pe ȚEAVĂ și argumente în linia de comandă:
#!/bin/bash
if [[ -p /proc/self/fd/0 ]]
then
PIPE=$(cat -)
echo "PIPE=$PIPE"
fi
echo "ARGS=$@"
Ieșire:
$ bash test arg1 arg2
ARGS=arg1 arg2
$ echo pipe_data1 | bash test arg1 arg2
PIPE=pipe_data1
ARGS=arg1 arg2
Explicație: atunci Când un script primește date prin țeavă, apoi stdin /proc/auto/fd/0 va fi o legătură simbolică la o conductă.
/proc/self/fd/0 -> pipe:[155938]
Dacă nu, acesta va fi punctul de la actualul terminal:
/proc/self/fd/0 -> /dev/pts/5
Bash dacă -p
opțiune poate verifica că este o conductă sau nu.
pisica
citește de la intrarea standard`.
Dacă vom folosi pisica
, atunci când nu există nici o stdin
, se va aștepta pentru totdeauna, de aceea am pus-o în interiorul "dacă" starea.