Đọc stdin vào một mảng bash


7

Tôi muốn thực hiện tương đương với:

list=()
while read i; do
  list+=("$i")
done <<<"$input"

với

IFS=$'\n' read -r -a list <<<"$input"

Tôi đang làm gì sai?

input=`/bin/ls /`

IFS=$'\n' read -r -a list <<<"$input"

for i in "${list[@]}"; do
  echo "$i"
done

Điều này sẽ in một danh sách /, nhưng tôi chỉ nhận được mục đầu tiên.


4
Nếu bạn thực sự cố gắng phân tích đầu ra của ls, đừng. Sử dụng list=(/*).
chepner

Câu trả lời:


11

Bạn phải sử dụng mapfile (hoặc từ đọc đồng nghĩa của nó , được giới thiệu trong bash 4.0):

mapfile -t list <<<"$input"

Một đọc gọi chỉ làm việc với một dòng, không phải toàn bộ đầu vào tiêu chuẩn.

read -a listđiền nội dung của dòng tiêu chuẩn đầu tiên vào mảng list. Trong trường hợp của bạn, bạn có binphần tử duy nhất trong danh sách `.


2
@cuonglm Điều IFSnày là vô ích, bởi vì mapfilekhông thực hiện bất kỳ phân tách từ nào trên đầu vào của nó.
chepner

@ StéphaneChazelas: Xấu của tôi, đã xóa nó.
cuonglm

5

Giải pháp cho Bash phiên bản 3 (và 4)

Tôi tình cờ đăng nhập vào hộp CentOS 5 chạy Bash 3 và tôi đã nghiên cứu giải pháp. Tôi đã nêu lên câu trả lời của cuonglm nhưng tôi nghĩ tôi cũng có thể đăng giải pháp mà tôi đã đưa ra để làm việc với Bash 3 (và 4). Tôi đã thử nó với một tệp có một khoảng trắng trong tên của nó và một tệp khác bắt đầu bằng -.

Thay vì

IFS=$'\n' read -r -a list <<<"$input"

chỉ cần sử dụng thay thế lệnh để tạo và điền vào mảng:

IFS=$'\n' # split on newline only
set -f    # disable globbing
list=($(printf "%s" "$input"))

Lưu ý: Điều này sẽ không hoạt động với tên tệp có dòng mới trong tên của chúng.


4

cho bashcác phiên bản không hỗ trợmapfile

IFS=$'\n' read -ra list -d '' <<< "$input"

nên làm mánh khóe


2
Một nhược điểm nhỏ; lệnh này sẽ luôn có trạng thái thoát khác không.
chepner

2
Cũng lưu ý rằng nó loại bỏ các yếu tố trống.
Stéphane Chazelas
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.