Làm thế nào để thoát các ký tự đặc biệt trong một chuỗi?


16

Giả sử $filegiữ một giá trị của một tên tập tin, nói Dr' A.tif. Trong lập trình bash, làm thế nào tôi có thể thoát khỏi trích dẫn đơn và bất kỳ ký tự đặc biệt nào khác $filemà không xóa ký tự đặc biệt?

Cập nhật ngày 9 tháng 7 năm 2014

Theo yêu cầu từ @Gilles , đoạn mã sau không thể xử lý Dr' A.tif:

files=$(find /path/ -maxdepth 1 -name "*.[Pp][Dd][Ff]" -o -name "*.[Tt][Ii][Ff]")
echo "${files}" > ${TEMP_FILE}
while read file
do
   newfile=$(echo "${file}" | sed 's, ,\\ ,g') ## line 1
done < ${TEMP_FILE}

Sau khi tôi đã cố gắng ra câu trả lời từ @Patrick trên line 1, có vẻ như để làm việc cho tôi. Nhưng nếu tôi có tập tin như Dr\^s A.tif, printflệnh không có vẻ hữu ích, nó sẽ hiển thị cho tôi Dr\^s\ A.tif. Nếu tôi tự thử nó trên bàn điều khiển như thế này:

printf "%q" "Dr\^s A.tif"

Tôi sẽ có đầu ra này:

Dr\\\^s\ A.tif

Bất kỳ ý tưởng làm thế nào để xử lý này?


3
trong bối cảnh nào bạn muốn sử dụng $ file? hoặc vấn đề này là gán chuỗi có ký tự đặc biệt cho tệp $?
cướp

Trên thực tế, lệnh find trả về cho tôi một mảng danh sách tập tin. Và sau đó tôi lặp qua danh sách tệp này thành biến tệp $.
huahsin68

2
Bạn đã được đưa ra một số câu trả lời đúng ở đây, nhưng có lẽ chúng không phải là câu trả lời cho câu hỏi mà bạn thực sự hỏi. Từ nhận xét của bạn ở đây, tôi nghi ngờ rằng bạn đang đi sai đường. Chúng tôi không thể giúp bạn nhiều vì bạn tiếp tục không hiển thị mã của mình. Tuy nhiên tôi khuyên bạn nên đọc Tại sao tập lệnh shell của tôi bị nghẹt trên khoảng trắng hoặc các ký tự đặc biệt khác? làm nền. Hiển thị kịch bản của bạn và giải thích những gì bạn muốn làm.
Gilles 'SO- ngừng trở nên xấu xa'

Câu trả lời:


14

Bạn có thể sử dụng printfnội dung với %qđể thực hiện điều này. Ví dụ:

$ file="Dr' A.tif"
$ printf '%q\n' "$file"
Dr\'\ A.tif

$ file=' foo$bar\baz`'
$ printf '%q\n' "$file"
\ foo\$bar\\baz\`

Từ tài liệu bash trên printf:

In addition to the standard format specifications described in printf(1)
and printf(3), printf interprets:

 %b       expand backslash escape sequences in the corresponding argument
 %q       quote the argument in a way that can be reused as shell input
 %(fmt)T  output the date-time string resulting from using FMT as a format
          string for strftime(3)

Điều này không hoạt động với một số trường hợp nhất định .eg khi bạn cần giữ dấu ngoặc kép.
dùng3467349

@ user3467349 nó hoạt động tốt với dấu ngoặc kép. Tôi cá là bạn đang thử một cái gì đó như printf '%s' "foo". Bạn cần hiểu cách phân tích cú pháp đối số hoạt động trong trình bao trước. Xem gnu.org/software/bash/manual/bash.html#Shell-Operation # 2 xảy ra trước # 6.
Patrick

Bạn có thể cung cấp một ví dụ về chuỗi này được in printfvà không có thao tác nào khácIt doesn't have a: ""
user3467349

Vấn đề của bạn không có gì để làm với printf. Vấn đề của bạn là bạn không muốn shell phân tích chuỗi của bạn. Để làm điều đó, bạn phải chuyển đầu vào của mình vào trình bao theo cách mà nó thậm chí không cố phân tích cú pháp. Một cách để làm điều này sẽ là read -r -p 'input: ' && printf '%q\n' "$REPLY", và cung cấp đầu vào khi được nhắc.
Patrick

1
Như tôi đã nói nhiều lần rồi. Không biết làm thế nào để truyền dữ liệu thô vào shell không phải là vấn đề printf. Có lẽ bạn nên đặt một câu hỏi thay vì chỉ trích một giải pháp không liên quan gì đến vấn đề của bạn.
Patrick

4

Thử:-

file=Dr\'\ A.tif
echo $file
Dr' A.tif

hoặc là

file="Dr' A.tif"
echo $file
Dr' A.tif

hoặc nếu chuỗi chứa một trích dẫn kép: -

file='Dr" A.tif'
echo $file
Dr" A.tif

Có những hướng dẫn tốt về thoát và trích dẫn trên mạng. Bắt đầu với một này .


1

Bạn không cần phải thoát bất kỳ tên tệp nào bạn đang xử lý trong tập lệnh. Việc thoát chỉ cần thiết nếu bạn muốn đặt tên tệp dưới dạng chữ trong tập lệnh hoặc chuyển một số tên tệp dưới dạng một luồng đầu vào sang tập lệnh khác.

Vì bạn đang lặp qua đầu ra của find, đây là một trong những cách đơn giản nhất (!) Để xử lý mọi đường dẫn có thể :

while IFS= read -r -d ''
do
    file_namex="$(basename -- "$REPLY"; echo x)"
    file_name="${file_namex%$'\nx'}"
    do_something -- "$file_name"
done <(find "$some_path" -exec printf '%s\0' {} +)

0

nhanh chóng và (rất) bẩn

find . | sed 's/^/"/' | sed 's/$/"/'

-1

Rất nhiều câu trả lời trong đó có câu trả lời được bình chọn hàng đầu bằng cách sử dụng printf "%q"sẽ không hoạt động trong mọi trường hợp mà không cần thao tác bổ sung. Tôi muốn đề xuất như sau (ví dụ dưới đây):

cat <<EOF; 2015-11-07T03:34:41Z app[postgres.0000]: [TAG] text-search query doesn't contain lexemes: "" EOF


Xin hỏi câu hỏi n00b nhưng bạn có thể giải thích cách bạn thực sự sử dụng câu hỏi này để thoát các ký tự trong một chuỗi không? Nếu tôi sao chép mã bạn viết vào thiết bị đầu cuối của mình, nó chỉ in ứng dụng 2015-11-07T03: 34: 41Z [postgres.0000]: [TAG] truy vấn tìm kiếm văn bản không chứa từ vựng: "" ... không có gì được thoát .
SharkAlley

Đó thực sự là vấn đề, tất cả các ký tự đặc biệt được hiểu là các ký tự theo nghĩa đen không phải vì ý nghĩa đặc biệt của chúng. Thay vào đó, hãy thử lặp lại "chuỗi trên" để thấy sự khác biệt.
user3467349
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.