Script Perl berikut ( my.pl
) dapat membaca dari file pada argumen baris perintah atau dari STDIN:
while (<>) {
print($_);
}
perl my.pl
akan membaca dari STDIN, sementara perl my.pl a.txt
akan membaca dari a.txt
. Ini sangat nyaman.
Ingin tahu apakah ada yang setara di Bash?
/proc/$$/fd/0
dan/dev/stdin
? Saya perhatikan yang terakhir tampaknya lebih umum dan terlihat lebih mudah.-r
Andaread
, sehingga tidak sengaja memakan\
karakter; gunakanwhile IFS= read -r line
untuk melestarikan spasi putih terkemuka dan tertinggal./bin/sh
- apakah Anda menggunakan shell selainbash
ataush
?Mungkin solusi paling sederhana adalah mengarahkan ulang stdin dengan operator pengalihan penggabungan:
Stdin adalah deskriptor file nol. Di atas mengirimkan input yang disalurkan ke skrip bash Anda ke less's stdin.
Baca selengkapnya tentang pengalihan deskriptor file .
sumber
<&0
dalam situasi ini - contoh Anda akan bekerja sama dengan atau tanpa itu - tampaknya, alat yang Anda panggil dari dalam skrip bash secara default melihat stdin yang sama dengan skrip itu sendiri (kecuali skrip yang menggunakannya terlebih dahulu).Inilah cara paling sederhana:
Pemakaian:
Untuk menetapkan stdin ke variabel, Anda dapat menggunakan:
STDIN=$(cat -)
atau hanyaSTDIN=$(cat)
karena operator tidak diperlukan (sesuai komentar @ mklement0 ).Untuk mengurai setiap baris dari input standar , coba skrip berikut:
Untuk membaca dari file atau stdin (jika argumen tidak ada), Anda dapat memperluas ke:
Lihat: Bagaimana membaca stdin ketika tidak ada argumen yang disampaikan? di stackoverflow SE
sumber
[ "$1" ] && FILE=$1 || FILE="-"
untukFILE=${1:--}
. (Quibble: lebih baik untuk menghindari variabel shell huruf besar semua untuk menghindari tabrakan nama dengan variabel lingkungan .)${1:--}
adalah POSIX-compliant, jadi ia harus bekerja di semua kerang mirip POSIX. Apa yang tidak akan bekerja di semua shell tersebut adalah substitusi proses (<(...)
); itu akan bekerja di bash, ksh, zsh, tetapi tidak di dash, misalnya. Juga, lebih baik menambahkan perintah-r
Andaread
, sehingga tidak sengaja memakan\
karakter; bertanggung jawabIFS=
untuk melestarikan spasi putih terkemuka dan tertinggal.echo
: jika suatu baris terdiri dari-e
,-n
atau-E
, itu tidak akan ditampilkan. Untuk mengatasinya, Anda harus menggunakanprintf
:printf '%s\n' "$line"
. Saya tidak memasukkannya dalam edit saya sebelumnya ... terlalu sering suntingan saya dibatalkan ketika saya memperbaiki kesalahan ini:(
.--
tidak ada gunanya jika argumen pertama adalah'%s\n'
IFS=
denganread
danprintf
bukanecho
.:)
.Saya pikir ini adalah jalan lurus ke depan:
-
-
sumber
read
membaca dari stdin secara default , jadi ada tidak perlu untuk< /dev/stdin
.The
echo
solusi menambahkan baris baru setiap kaliIFS
istirahat input stream. Jawaban @ fgm dapat dimodifikasi sedikit:sumber
read
's perilaku: sementararead
tidak berpotensi dibagi menjadi beberapa token oleh karakter. terkandung dalam$IFS
, itu hanya mengembalikan token tunggal jika Anda hanya menentukan nama variabel tunggal (tetapi trims dan memimpin dan mengikuti spasi putih secara default).read
dan$IFS
-echo
itu sendiri menambahkan baris baru tanpa-n
bendera. "Utilitas gema menulis operan tertentu, dipisahkan oleh karakter tunggal kosong (` ') dan diikuti oleh karakter baris baru (`\ n'), ke output standar."\n
ditambahkan olehecho
: Perl$_
termasuk baris yang berakhir\n
dari baris yang dibaca, sedangkan bashread
tidak. (Namun, seperti yang ditunjukkan @gniourf_gniourf di tempat lain, pendekatan yang lebih kuat adalah untuk digunakanprintf '%s\n'
sebagai penggantiecho
).Loop Perl dalam pertanyaan membaca dari semua argumen nama file pada baris perintah, atau dari input standar jika tidak ada file yang ditentukan. Jawaban yang saya lihat sepertinya memproses satu file atau input standar jika tidak ada file yang ditentukan.
Meskipun sering diejek secara akurat sebagai UUOC (Penggunaan yang Tidak Berguna
cat
), ada kalanyacat
alat terbaik untuk pekerjaan itu, dan dapat diperdebatkan bahwa ini adalah salah satunya:Satu-satunya downside ke ini adalah bahwa ia menciptakan sebuah pipa berjalan di sub-shell, sehingga hal-hal seperti penugasan variabel dalam
while
loop tidak dapat diakses di luar pipa. Thebash
cara mengatasinya adalah Proses Pergantian :Ini meninggalkan
while
loop berjalan di shell utama, sehingga variabel yang diatur dalam loop dapat diakses di luar loop.sumber
>>EOF\n$(cat "$@")\nEOF
. Akhirnya, quibble:while IFS= read -r line
adalah perkiraan yang lebih baik dari apa yangwhile (<>)
dilakukan di Perl (mempertahankan spasi putih terdepan dan tertinggal - meskipun Perl juga menjaga trailing\n
).Perilaku Perl, dengan kode yang diberikan dalam OP dapat mengambil tidak ada atau beberapa argumen, dan jika argumen adalah tanda hubung tunggal
-
ini dipahami sebagai stdin. Selain itu, selalu memungkinkan untuk memiliki nama file$ARGV
. Tidak ada jawaban yang diberikan sejauh ini yang benar-benar meniru perilaku Perl dalam hal ini. Inilah kemungkinan Bash murni. Caranya adalah menggunakan denganexec
tepat.Nama file tersedia di
$1
.Jika tidak ada argumen yang diberikan, kami secara artifisial menetapkan
-
sebagai parameter posisi pertama. Kami kemudian mengulangi parameter. Jika parameter tidak-
, kami mengarahkan input standar dari nama file denganexec
. Jika pengalihan ini berhasil, kami mengulang denganwhile
loop. Saya menggunakanREPLY
variabel standar , dan dalam hal ini Anda tidak perlu mengatur ulangIFS
. Jika Anda ingin nama lain, Anda harus mengatur ulangIFS
seperti itu (kecuali, tentu saja, Anda tidak menginginkannya dan tahu apa yang Anda lakukan):sumber
Lebih akurat...
sumber
IFS=
dan-r
keread
perintah memastikan bahwa setiap baris dibaca tidak dimodifikasi (termasuk spasi spasi awal dan akhir).Silakan coba kode berikut:
sumber
read
tanpaIFS=
dan-r
, dan orang miskin$line
tanpa tanda kutip yang sehat.read -r
notasi. IMO, POSIX salah; opsi harus mengaktifkan makna khusus untuk trailing backslash, bukan menonaktifkannya - sehingga skrip yang ada (dari sebelum POSIX ada) tidak akan rusak karena-r
dihilangkan. Saya mengamati, bagaimanapun, bahwa itu adalah bagian dari IEEE 1003.2 1992, yang merupakan versi paling awal dari shell POSIX dan standar utilitas, tetapi itu ditandai sebagai tambahan bahkan kemudian, jadi ini menggerutu tentang peluang yang sudah lama hilang. Saya tidak pernah mengalami masalah karena kode saya tidak digunakan-r
; Saya pasti beruntung. Abaikan aku dalam hal ini.-r
harus menjadi standar. Saya setuju bahwa tidak mungkin dalam kasus di mana tidak menggunakannya menyebabkan masalah. Padahal, kode rusak adalah kode rusak. Suntingan saya pertama-tama dipicu oleh$line
variabel yang buruk itu yang terlewatkan kutipnya. Saya memperbaikiread
sementara saya berada di itu. Saya tidak memperbaikiecho
karena itulah jenis pengeditan yang dibatalkan.:(
.Kode
${1:-/dev/stdin}
hanya akan mengerti argumen pertama, jadi, bagaimana dengan ini.sumber
Saya tidak menemukan jawaban ini yang dapat diterima. Secara khusus, jawaban yang diterima hanya menangani parameter baris perintah pertama dan mengabaikan sisanya. Program Perl yang ia coba tiru menangani semua parameter baris perintah. Jadi jawaban yang diterima bahkan tidak menjawab pertanyaan. Jawaban lain menggunakan ekstensi bash, tambahkan perintah 'cat' yang tidak perlu, hanya berfungsi untuk kasus sederhana dari gema input ke output, atau hanya rumit yang tidak perlu.
Namun, saya harus memberi mereka kredit karena mereka memberi saya beberapa ide. Inilah jawaban lengkapnya:
sumber
Saya menggabungkan semua jawaban di atas dan membuat fungsi shell yang sesuai dengan kebutuhan saya. Ini dari terminal cygwin dari 2 mesin Windows10 saya di mana saya memiliki folder bersama di antara mereka. Saya harus bisa menangani yang berikut ini:
cat file.cpp | tx
tx < file.cpp
tx file.cpp
Di mana nama file tertentu ditentukan, saya harus menggunakan nama file yang sama saat menyalin. Di mana aliran data input telah disalurkan melalui, maka saya perlu membuat nama file sementara yang memiliki jam menit dan detik. Mainfolder bersama memiliki subfolder dari hari-hari dalam seminggu. Ini untuk tujuan organisasi.
Lihatlah, naskah akhir untuk kebutuhan saya:
Jika ada cara yang dapat Anda lihat untuk lebih mengoptimalkan ini, saya ingin tahu.
sumber
Berikut ini berfungsi dengan standar
sh
(Diuji dengandash
pada Debian) dan cukup mudah dibaca, tapi itu masalah selera:Detail: Jika parameter pertama tidak kosong maka
cat
file itu, ataucat
input standar. Kemudian output dari seluruhif
pernyataan diproses olehcommands_and_transformations
.sumber
cat "${1:--}" | any_command
. Membaca ke variabel shell dan menggema mereka mungkin bekerja untuk file kecil tetapi tidak skala dengan baik.[ -n "$1" ]
dapat disederhanakan[ "$1" ]
.Yang ini mudah digunakan di terminal:
sumber
Bagaimana tentang
sumber
cat
akan ditempatkan ke dalam baris perintah. Baris perintah memiliki ukuran maksimum. Juga ini tidak akan membaca baris demi baris, tetapi kata demi kata.