Làm cách nào để gán ls cho một mảng trong Linux Bash?


Câu trả lời:


109

Nó sẽ là cái này

array=($(ls -d */))

CHỈNH SỬA: Xem giải pháp của Gordon Davisson để có câu trả lời tổng quát hơn (nghĩa là nếu tên tệp của bạn chứa các ký tự đặc biệt). Câu trả lời này chỉ là một sửa cú pháp.


14
Điều này sẽ không hoạt động chính xác nếu tên thư mục chứa khoảng trắng.
chepner

1
Để giải quyết vấn đề về khoảng trắng hoặc ký tự đặc biệt, trước tiên hãy khai báo mảng không có bất kỳ giá trị nào, sau đó sử dụng tích hợp sẵn ARR+=('$(ls -d */)')để chỉnh sửa các phần tử trong một mảng, trong khi sử dụng dấu ngoặc kép để xử lý các ký tự đặc biệt, để thêm hoặc xóa các phần tử của mảng đó mảng. Dấu ngoặc kép duy trì các ký tự chữ và loại bỏ bất kỳ yêu cầu thoát nào để xử lý chúng trong tên thư mục.
Yokai

@Yokai Đề xuất của bạn nghe có vẻ tuyệt vời nhưng không phù hợp với tôi trên Ubuntu 16.04 hoặc MacOs. Bash mở rộng mã giữa dấu nháy đơn như thế này: declare -a ARR; ARR+=('$(ls -d "$INPUT_DIR"/*)')lợi nhuận chỉ$(ls -d $INPUT_DIR/*)
Agile Bean

1
Lỗi của tôi. Đó phải là dấu ngoặc kép để thay thế lệnh có thể được mở rộng. ARR+=("$(ls -d */)")nên làm việc. Nếu không chỉ cho tôi biết.
Yokai

2
@Yokai, chỉ thêm một phần tử tổng số (với một loạt các dòng mới trong đó), không phải một phần tử cho mỗi thư mục.
Charles Duffy

76

Bất cứ khi nào có thể, bạn nên tránh phân tích cú pháp đầu ra của ls(xem wiki của Greg về chủ đề này ). Về cơ bản, đầu ra của lssẽ không rõ ràng nếu có các ký tự hài hước trong bất kỳ tên tệp nào. Nó cũng thường lãng phí thời gian. Trong trường hợp này, khi bạn thực thi ls -d */, điều xảy ra là trình bao mở rộng */thành danh sách các thư mục con (đã chính xác là những gì bạn muốn), chuyển danh sách đó dưới dạng các đối số ls -d, nhìn vào từng đối số, nói "vâng, đó là một thư mục được rồi ”và in nó (ở định dạng không nhất quán và đôi khi không rõ ràng). Các lslệnh không được làm bất cứ điều gì hữu ích!

Chà, được rồi, nó đang làm một điều hữu ích: nếu không có thư mục con nào, */sẽ được sang trái như cũ, lssẽ tìm kiếm thư mục con có tên "*", không tìm thấy nó, in một thông báo lỗi rằng nó không tồn tại (để stderr), và không in "* /" (sang stdout).

Cách rõ ràng hơn để tạo một mảng tên thư mục con là sử dụng global ( */) mà không chuyển nó tới ls. Nhưng để tránh đặt "* /" trong mảng nếu không có thư mục con thực sự, bạn nên đặt nullglob trước (một lần nữa, hãy xem wiki của Greg ):

shopt -s nullglob
array=(*/)
shopt -u nullglob # Turn off nullglob to make sure it doesn't interfere with anything later
echo "${array[@]}"  # Note double-quotes to avoid extra parsing of funny characters in filenames

Nếu bạn muốn in thông báo lỗi nếu không có thư mục con nào, tốt hơn hết bạn nên tự thực hiện:

if (( ${#array[@]} == 0 )); then
    echo "No subdirectories found" >&2
fi

2
Cảm ơn bình luận của bạn, mặc dù không được đánh dấu là câu trả lời nhưng nó khá nhiều thông tin và tôi đánh giá cao nó.
Jake H

Điều gì sẽ xảy ra nếu bạn không muốn có /trong tên dir?
shinzou

Các vấn đề / vấn đề được nêu trong wiki của greg không phải là những thứ không thể dễ dàng giải quyết bằng các cấu trúc có điều kiện đơn thuần. lslà một lệnh đơn giản. Đầu ra của nó là chuỗi. Bash cực kỳ giỏi trong việc phân tích chuỗi. Regex thích hợp là tất cả những gì cần thiết để phân tích cú pháp lsđầu ra một cách an toàn .
Yokai

@Yokai Các phiên bản lskhác nhau làm những việc khác nhau với các ký tự vui nhộn / không in trong tên tệp, vì vậy không có cách nào nhất quán để phân tích đầu ra của nó thành danh sách tên tệp. Và như tôi đã nói, nó không thực sự làm bất cứ điều gì hữu ích: nếu bạn phân tích cú pháp chính xác đầu ra của nó ls -d */, bạn sẽ kết thúc với chính xác thứ mà bạn nhận được trực tiếp từ đó */(ngoại trừ khi không có kết quả phù hợp và điều đó dễ dàng kiểm tra).
Gordon Davisson,

Tóm lại: A lazy sysadmin is a good sysadmin.Có lẽ cách lsphân tích cú pháp của riêng tôi dành riêng cho phiên bản tôi có, hoặc phiên bản tôi đã quen, nhưng cho đến nay chúng không có vấn đề gì trên các bản phân phối linux mà tôi đã thử nghiệm. Tôi chỉ có thể nói từ kinh nghiệm.
Yokai

7

Điều này sẽ in các tệp trong các thư mục đó từng dòng một.

array=(ww/* ee/* qq/*)
printf "%s\n" "${array[@]}"
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.