Làm cách nào để đọc nhiều dòng từ STDIN thành một biến?


24

Tôi đã googling câu hỏi này vô ích. Tôi đang tự động hóa một quy trình xây dựng tại nơi làm việc và tất cả những gì tôi đang cố gắng là lấy số phiên bản và một mô tả nhỏ về bản dựng có thể là nhiều dòng. Hệ thống này chạy trên OSX 10.6.8.

Tôi đã thấy mọi thứ từ việc sử dụng CAT đến xử lý từng dòng khi cần thiết. Tôi không thể tìm ra những gì tôi nên sử dụng và tại sao.

Nỗ lực

read -d '' versionNotes

Kết quả trong đầu vào bị cắt xén nếu người dùng phải sử dụng phím xóa lùi. Ngoài ra, không có cách nào tốt để chấm dứt đầu vào vì ^ D không chấm dứt và ^ C chỉ thoát khỏi quy trình.

read -d 'END' versionNotes

Hoạt động ... nhưng vẫn bị cắt đầu vào nếu cần phím backspace.

while read versionNotes
do
  echo "  $versionNotes" >> "source/application.yml"
done

Không kết thúc đúng cách đầu vào (vì tôi đã quá muộn để tìm kiếm kết quả khớp với chuỗi trống).


Bạn đang nhận được thông tin này từ người dùng, đúng không?
glenn jackman

Chính xác; Tôi muốn người dùng nhập thông tin này vào thiết bị đầu cuối khi thực thi tập lệnh.
Robert K

1
Bạn đã không làm cho mình rõ ràng, tôi muốn nói.
poige

Câu trả lời:


20

man bash đề cập đến «đào

Lệnh thay thế $ (tệp cat) có thể được thay thế bằng $ (<file) tương đương nhưng nhanh hơn.

Cẩu »

$ myVar=$(</dev/stdin)
hello
this is test
$ echo $myVar
hello this is test
$ echo "$myVar"
hello
this is test

và tôi đồng ý rằng điều này đáng được đề cập - echo "$myVar"sẽ hiển thị đầu vào như đã được đưa ra.


1
Làm thế nào để dừng lại sau khi nhập đa dòng? Nếu tôi nhấn Ctrl C thì nó dừng nhưng biến không được lưu!
Nikhil

2
Thiết bị đầu cuối UNIX® làm có "kỷ luật": en.wikipedia.org/wiki/Line_discipline • Kiểm tra nó ra những gì hiện "eof" trung bình • Đỗ đọc man stty, tìm hiểu làm thế nào để cài đặt hiện thời
poige

2
ctrl-d dừng lại.
freb

9

Thử đi:

user@host:~$ read -d '' x <<EOF
> mic
> check
> one
> two
> EOF

Không ngắt dòng:

user@host:~$ echo $x
mic check one two

Với ngắt dòng:

user@host:~$ echo "$x"
mic
check
one
two

2
-d ''chính xác là những gì tôi cần. Cảm ơn
Bruno Bronosky

@Bruno Niềm vui của tôi; đó là một khó khăn Đặc biệt là thoạt nhìn, nó trông khá chuẩn. Có thể khá hữu ích mặc dù, một khi bạn có được sự khác biệt của các đặc điểm riêng.
lên tiếng vào

8

Tham khảo Hướng dẫn Bash tuyệt vời cho tất cả các nhu cầu kịch bản bash của bạn.

Cụ thể, Câu hỏi thường gặp về Bash chứa điều này ở số 1:

Làm cách nào tôi có thể đọc một tệp (luồng dữ liệu, biến) theo từng dòng (và / hoặc từng trường)?


Bạn nói để sử dụng read -r, nhưng làm thế nào để tôi có được nó từ STDIN? Tôi đã cố gắng sử dụng read -rsớm.
Robert K

Nó đọc từ stdin theo mặc định.
thích nghi

2

Tôi đã giải quyết vấn đề này bằng cách xử lý từng dòng cho đến khi tôi đưa ra một dòng trống. Nó hoạt động đủ tốt cho tình hình của tôi. Nhưng nếu ai đó muốn thêm một giải pháp tốt hơn, hãy thoải mái làm điều đó.

echo "---
notes: |" > 'version.yml'

while read line
do
  # break if the line is empty
  [ -z "$line" ] && break
  echo "  $line" >> "source/application.yml"
done

Sử dụng read -rthay thế.
thích nghi

2

Bạn có thể bắt đầu một trình soạn thảo như vim, pico ...

${VISUAL:-${EDITOR:-vi}} source/application.yml

Ừm ... làm thế nào mà trả lời câu hỏi của OP theo bất kỳ cách nào?
thích nghi

Anh ta có thể bắt đầu biên tập từ kịch bản.
Mircea Vutcovici

Và điều đó thực hiện những gì, chính xác? Ông muốn sử dụng văn bản từ một tập tin trong kịch bản, không ghi thông tin để một tập tin.
thích nghi

Anh ta không đọc văn bản từ người dùng và viết nó vào một tập tin. Xin vui lòng đọc các ý kiến ​​thêm vào câu hỏi.
Mircea Vutcovici

1

Đầu tiên một vài sửa chữa:

  1. Để cho phép "phiên bản" trên dòng sử dụng sử dụng đường đọc -e(để bạn có lịch sử bash và tất cả các tính năng chỉnh sửa)
  2. -dchỉ mất một nhân vật. Ví dụ: từ 'END' mất 'E' và bất cứ khi nào người dùng viết 'E' thì việc đọc dừng lại (tôi đoán đó không phải là điều bạn muốn ...)

Có một vài khả năng để làm điều này. Tôi sẽ đọc từng dòng một và dừng lại khi tìm thấy một dòng trống (mặc dù bạn có thể đặt bất kỳ từ dừng nào):

unset tmp
while :
do 
 read line
 [[ $line == "" ]] && tmp="${tmp:0:$((${#tmp}-1))}" && break
 tmp="$tmp"$line$'\n'
done

0

Bạn có một vài phương pháp.

Một trong những phương pháp đơn giản nhất là:

MYVAR=$(yourcommand)
echo $"MYVAR"

Ví dụ:

MYVAR=$(ls /)
echo $"MYVAR"

Ngoại trừ tôi không thực hiện một lệnh shell như LS. Tôi đang yêu cầu đầu vào nhiều dòng từ người dùng.
Robert K

Đây là thực tế rất xấu; không xử lý đầu ra của ls!
thích nghi

@adaptr Chúng tôi đã nghe tất cả trước đây, bạn có phiền đề xuất một lựa chọn tốt, xin vui lòng?
lên tiếng vào

0

Chúng tôi đang sử dụng một cấu trúc bằng cách sử dụng xargs và ctrl-d để phá vỡ. Tôi không hoàn toàn hài lòng với nó, nhưng nó chắc chắn thực hiện công việc lấy đầu vào của nhiều người dùng và nhồi nó vào một biến (định dạng nguyên vẹn). (Bài tập thứ nhất và thứ ba thêm dấu ngoặc kép xung quanh nội dung của đầu vào xargs.)

    printf "\\033[1mWhen finished hit ctrl-d on a new line to proceed.\\033[0m  \\n\\n" 
    # this will load the user's input into a variable instead of a file 
    reminderBody="\"" 
    reminderBody+=$( xargs -0 ) 
    reminderBody+="\"" 

Chúng tôi sử dụng reminderBody làm chủ đề của một email được gửi qua thư (thông qua bash).


-1

Xem: http://tldp.org/LDP/abs/html/iternal.html#READR

Sử dụng readvà lưu ý rằng nếu bạn kết thúc một dòng với \dòng mới sẽ bị bỏ qua. Vì vậy, bạn có thể làm:

#! / bin / bash

đọc -p "phiên bản:" phiên bản
phiên bản tiếng vang $

# nhập một số dòng dài đầu vào và kết thúc bằng "\", sau đó nhập đơn giản vào cuối
đọc -p "mô tả:" mô tả
echo -e "$ phiên bản \ n $ mô tả >> yourfile.txt

Nếu tôi chỉ muốn một đoạn có ngắt dòng bị bỏ qua, có. Nhưng vì đây là danh sách các ghi chú phát hành được tạo cho tập lệnh xây dựng, tôi cần có khả năng duy trì các ngắt dòng đó; Tôi có thể thử nhập một danh sách gạch đầu dòng, ví dụ.
Robert K

ABS là một quái vật của tỷ lệ khủng khiếp. 90% là sai.
thích nghi

Nó không phải là xấu.
lên tiếng vào
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.