Lỗi script Bash với các chuỗi có đường dẫn có dấu cách và ký tự đại diện


25

Tôi gặp khó khăn khi lấy những điều cơ bản của Bash scripting xuống. Đây là những gì tôi có cho đến nay:

#!/bin/bash
FILES="/home/john/my directory/*.txt"

for f in "${FILES}"
do
  echo "${f}"
done

Tất cả những gì tôi muốn làm là liệt kê tất cả các .txttệp trong một forvòng lặp để tôi có thể làm mọi thứ với chúng. Nhưng không gian trong my directoryvà dấu hoa thị *.txtchỉ không chơi độc đáo. Tôi đã thử sử dụng nó có và không có dấu ngoặc kép, có và không có dấu ngoặc nhọn trên tên biến và vẫn không thể in tất cả các .txttệp.

Đây là một điều rất cơ bản, nhưng tôi vẫn đang vật lộn vì tôi mệt mỏi và không thể nghĩ thẳng.

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

Tôi đã có thể áp dụng thành công tập lệnh ở trên nếu PHIM của tôi không có dấu cách hoặc dấu hoa thị ... Tôi đã phải thử nghiệm hoặc không sử dụng dấu ngoặc kép và dấu ngoặc kép để làm cho nó hoạt động. Nhưng khoảnh khắc tôi có cả không gian và dấu hoa thị, nó làm mọi thứ rối tung lên.

Câu trả lời:


33

Bên trong dấu ngoặc kép, *sẽ không mở rộng thành một danh sách các tập tin. Để sử dụng ký tự đại diện thành công, nó phải nằm ngoài dấu ngoặc kép.

Ngay cả khi ký tự đại diện đã mở rộng, biểu thức "${FILES}"sẽ dẫn đến một chuỗi, không phải là danh sách các tệp.

Một cách tiếp cận sẽ hiệu quả là:

#!/bin/bash
DIR="/home/john/my directory/"
for f in "$DIR"/*.txt
do
  echo "${f}"
done

Ở trên, tên tệp có dấu cách hoặc ký tự khó khác sẽ được xử lý chính xác.

Một cách tiếp cận nâng cao hơn có thể sử dụng mảng bash:

#!/bin/bash
FILES=("/home/john/my directory/"*.txt)
for f in "${FILES[@]}"
do
  echo "${f}"
done

Trong trường hợp này, FILESlà một mảng các tên tệp. Các parens xung quanh định nghĩa làm cho nó một mảng. Lưu ý rằng *bên ngoài dấu ngoặc kép. Cấu trúc "${FILES[@]}"là một trường hợp đặc biệt: nó sẽ mở rộng thành một danh sách các chuỗi trong đó mỗi chuỗi là một trong các tên tệp. Tên tệp có dấu cách hoặc ký tự khó khác sẽ được xử lý chính xác.


1
thật tuyệt khi làm việc
John

Nó đáng chú ý là nếu bạn đang đi qua những con đường như xung quanh này thông qua chức năng, bạn cần đảm bảo bạn trích dẫn biến ngày của riêng mình chứ không phải là concatenating nó như là một phần của một chuỗi lớn hơn: for f in "$DIR"/*.txt= tốt for f in "$DIR/*.txt"= phá vỡ
pospi

7

Mặc dù việc sử dụng các mảng như được hiển thị bởi John1024 có ý nghĩa hơn rất nhiều, ở đây, bạn cũng có thể sử dụng toán tử split + global (không để lại một biến vô hướng).

Vì bạn chỉ muốn phần toàn cầu của toán tử đó, bạn cần tắt phần tách :

#! /bin/sh -
# that also works in any sh, so you don't even need to have or use bash

file_pattern="/home/john/my directory/*.txt"
# all uppercase variables should be reserved for environment variables

IFS='' # disable splitting

for f in $file_pattern # here we're not quoting the variable so
                       # we're invoking the split+glob operator.
do
  printf '%s\n' "$f" # avoid the non-reliable, non-portable "echo"
done

0

Những gì bạn có thể làm là chỉ để lại các ký tự đại diện bên ngoài dấu ngoặc kép.
Một cái gì đó như:
cho một trong "các tập tin với không gian" * "txt"
làm
xử lý xong
làm
Nếu ký tự đại diện tự mở rộng ra không gian, sau đó bạn sẽ cần t sử dụng một tập tin mỗi cách tiếp cận dòng, giống như ls -l sử dụng để tạo ra các danh sách tập tin và sử dụng bash đọc để có được mỗi tập tin.


-1

Khi bạn muốn xử lý tập hợp các tệp, bạn xem xét, tại tên của chúng có thể là khoảng trắng hoặc mã scape khác sẽ ở đó, vì vậy trước khi bắt đầu quy trình của bạn như for loophoặc find commandđặt thành IFS bash env variable:

IFS=$(echo -en "\n\b")
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.