Làm thế nào tôi có thể thoát khỏi một trích dẫn kép trong dấu ngoặc kép?


286

Làm thế nào tôi có thể thoát dấu ngoặc kép trong chuỗi kép trong Bash?

Ví dụ: trong tập lệnh shell của tôi

#!/bin/bash

dbload="load data local infile \"'gfpoint.csv'\" into table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY \"'\n'\" IGNORE 1 LINES"

Tôi không thể lấy dấu ENCLOSED BY '\"'ngoặc kép để thoát chính xác. Tôi không thể sử dụng dấu ngoặc đơn cho biến của mình, vì tôi muốn sử dụng biến $dbtable.




2
@kenorb Không giống như một bản sao của câu hỏi đó ...
Đánh dấu


@Daenyth Đây không phải là loại lệnh bạn mong muốn người dùng cuối có quyền truy cập. Các tập lệnh tải hàng loạt thường được chạy trên máy chủ bởi người dùng đáng tin cậy (chẳng hạn như quản trị viên hệ thống hoặc nhà phát triển). Có, nếu người dùng cuối kiểm soát giá trị của $dbtable, sẽ có rủi ro. Tuy nhiên, điều này sẽ rất không phổ biến vì người dùng cuối thường không SSH vào máy để tải dữ liệu của họ.
jpmc26

Câu trả lời:


285

Sử dụng dấu gạch chéo ngược:

echo "\""     # Prints one " character.

9
Không làm việc. x=ls; if [ -f "$(which "\""$x"\"")" ]; then echo exists; else echo broken; fi;cho bị hỏng trong khi ... [ -f "$(which $x)" ]; ...hoặc ... [ -f $(which "$x") ]; ...làm việc tốt Các vấn đề sẽ phát sinh khi một trong hai $xhoặc kết quả của việc $(which "$x")đưa ra bất cứ thứ gì có khoảng trắng hoặc ký tự đặc biệt khác. Một cách giải quyết là sử dụng một biến để giữ kết quả which, nhưng bash có thực sự không có khả năng thoát khỏi một trích dẫn hay tôi đang làm gì đó sai?
Luc

Tôi đang cố gắng sử dụng grep -oh "\"\""$counter"\""\w*" như sau như một phần của cú pháp bash trong đó $counterlà một biến. nó không thích bất kỳ suy nghĩ nào
Jay D

82

Một ví dụ đơn giản về thoát dấu ngoặc kép trong trình bao:

$ echo 'abc'\''abc'
abc'abc
$ echo "abc"\""abc"
abc"abc

Nó được thực hiện bằng cách hoàn thành một cái đã mở ( '), đặt cái đã thoát ( \'), rồi mở cái khác ( ').

Cách khác:

$ echo 'abc'"'"'abc'
abc'abc
$ echo "abc"'"'"abc"
abc"abc

Nó được thực hiện bằng cách hoàn thành đã mở một ( '), đặt một trích dẫn trong một trích dẫn khác ( "'"), và sau đó mở một ( ') khác.

Ví dụ khác: Thoát dấu ngoặc đơn trong chuỗi trích dẫn đơn


1
Tôi đã thử sh -c "echo '{" key ":" value "}'" và thậm chí sh -c "echo '{' '"' 'key' '"' ':' '"' 'value' '"' '}' "trong nỗ lực đưa khóa từ và giá trị vào dấu ngoặc kép, nhưng trong cả hai trường hợp, tôi đã nhận được {key: value}
Igor Yagolnitser

1
Điều này có vẻ phức tạp không cần thiết cho dấu ngoặc kép: echo "abc\"abc"đủ để tạo ra abc"abcnhư trong câu trả lời của Peter.
divenex

2
Trong ví dụ đơn giản này thực sự, nhưng trong các trường hợp phức tạp của dấu ngoặc kép, có thể cần phải làm điều này và ví dụ của @ kenorb đã giúp tôi tìm ra cách xử lý các trường hợp đó.
prosoitos

63

Tôi không biết tại sao vấn đề cũ này lại xuất hiện ngày hôm nay trong danh sách được gắn thẻ Bash, nhưng chỉ trong trường hợp cho các nhà nghiên cứu trong tương lai, hãy nhớ rằng bạn có thể tránh thoát bằng cách sử dụng mã ASCII của các ký tự bạn cần lặp lại.

Thí dụ:

 echo -e "This is \x22\x27\x22\x27\x22text\x22\x27\x22\x27\x22"
 This is "'"'"text"'"'"

\x22 là mã ASCII (ở dạng hex) cho dấu ngoặc kép và \x27 cho dấu ngoặc đơn. Tương tự như vậy bạn có thể lặp lại bất kỳ nhân vật.

Tôi cho rằng nếu chúng ta cố gắng lặp lại chuỗi trên bằng dấu gạch chéo ngược, chúng ta sẽ cần một tiếng vang ngược hai hàng lộn xộn ... :)

Đối với phép gán biến này là tương đương:

 $ a=$'This is \x22text\x22'
 $ echo "$a"
 This is "text"

Nếu biến đã được đặt bởi chương trình khác, bạn vẫn có thể áp dụng dấu ngoặc kép / đơn với công cụ sed hoặc tương tự.

Thí dụ:

 $ b="Just another text here"
 $ echo "$b"
 Just another text here
 $ sed 's/text/"'\0'"/' <<<"$b" #\0 is a special sed operator
 Just another "0" here #this is not what i wanted to be
 $ sed 's/text/\x22\x27\0\x27\x22/' <<<"$b"
 Just another "'text'" here #now we are talking. You would normally need a dozen of backslashes to achieve the same result in the normal way.

1
+1 vì nó đã giải quyết vấn đề thêm biến PS1 vào ~ / .profile echo 'export PS1='\[\033[00;31m\]${?##0}$([ $? -ne 0 ] && echo \x22 \x22)\[\033[00;32m\]\u\[\033[00m\]@\[\033[00;36m\]\h\[\033[00m\][\[\033[01;33m\]\d \t\[\033[00m\]] \[\033[01;34m\]\w\n\[\033[00m\]$( [ ${EUID} -ne 0 ] && echo \x22$\x22 || echo \x22#\x22 ) '' >> ~/.profile
Yassine ElBadaoui

1
Đây là câu trả lời! Tôi yêu bạn
Miguel Rojas Cortés

28

Bash cho phép bạn đặt các chuỗi một cách ngẫu nhiên, và cuối cùng chúng sẽ được dán lại với nhau.

Vậy đây:

$ echo "Hello"', world!'

sản xuất

Hello, world!

Bí quyết là xen kẽ giữa các chuỗi đơn và đôi trích dẫn theo yêu cầu. Thật không may, nó nhanh chóng trở nên rất lộn xộn. Ví dụ:

$ echo "I like to use" '"double quotes"' "sometimes"

sản xuất

I like to use "double quotes" sometimes

Trong ví dụ của bạn, tôi sẽ làm nó như thế này:

$ dbtable=example
$ dbload='load data local infile "'"'gfpoint.csv'"'" into '"table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '"'"'"' LINES "'TERMINATED BY "'"'\n'"'" IGNORE 1 LINES'
$ echo $dbload

tạo ra đầu ra sau:

load data local infile "'gfpoint.csv'" into table example FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY "'\n'" IGNORE 1 LINES

Thật khó để thấy những gì đang diễn ra ở đây, nhưng tôi có thể chú thích nó bằng cách sử dụng các trích dẫn Unicode. Sau đây sẽ không hoạt động trong bash - nó chỉ để minh họa:

dbload=' load data local infile "'‘ 'gfpoint.csv'’' " into'‘ table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '’' "'‘ ' LINES’' TERMINATED BY "'‘ '\n'’' " IGNORE 1 LINES'

Các trích dẫn như của '' 'ở trên sẽ được giải thích bằng bash. Các trích dẫn như " 'sẽ kết thúc trong biến kết quả.

Nếu tôi đưa ra cách xử lý tương tự với ví dụ trước đó, thì nó sẽ như thế này:

$ echoI like to use' "double quotes"' sometimes


4
Ôi ... đó là một số thứ xấu xí.
Bạch tuộc ma thuật Urn

17

Hãy xem printf ...

#!/bin/bash
mystr="say \"hi\""

Không sử dụng printf

echo -e $mystr

Đầu ra: nói "hi"

Sử dụng printf

echo -e $(printf '%q' $mystr)

Đầu ra: nói \ "hi \"


2
Lưu ý rằng cũng printfthoát được nhiều nhân vật hơn, chẳng hạn như ', ()
David Pärsson

printf %qtạo chuỗi sẵn sàng cho eval, không được định dạng cho echo -e.
Charles Duffy

2
Không có lý do để bọc printfvới việc sử dụng vô dụngecho . Cả hai ví dụ của bạn đã trích dẫn bị hỏng. Cách khắc phục thích hợp là trích dẫn hai biến.
tripleee

15

Lưu trữ ký tự trích dẫn kép dưới dạng biến:

dqt = '"'
echo "Dấu ngoặc kép $ {dqt} X $ {dqt} bên trong chuỗi trích dẫn kép"

Đầu ra:

Dấu ngoặc kép "X" bên trong chuỗi trích dẫn kép

39
Bash thực sự là ngôn ngữ tồi tệ nhất
Andy Ray

@ 12oclocker, câu trả lời của bạn thật tuyệt vời: D! đặc biệt khi sử dụng với lệnh "sed", nó đã cứu ngày của tôi!
Artanis Zeratul

11

Sử dụng $ "chuỗi".

Trong ví dụ này, nó sẽ là,

dbload = $ "tải dữ liệu cục bộ lưu trữ cục bộ

Lưu ý (từ trang người đàn ông ):

Một chuỗi trích dẫn kép có trước ký hiệu đô la ($ "chuỗi") sẽ khiến chuỗi được dịch theo ngôn ngữ hiện tại. Nếu miền địa phương hiện tại là C hoặc POSIX, ký hiệu đô la sẽ bị bỏ qua. Nếu chuỗi được dịch và thay thế, thay thế được trích dẫn kép.


3
Thật tuyệt, không biết điều đó.
David Kierans

-5

Thêm "\"trước khi trích dẫn kép để thoát khỏi nó, thay vì\

#! /bin/csh -f

set dbtable = balabala

set dbload = "load data local infile "\""'gfpoint.csv'"\"" into table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '"\""' LINES TERMINATED BY "\""'\n'"\"" IGNORE 1 LINES"

echo $dbload
# load data local infile "'gfpoint.csv'" into table balabala FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY "''" IGNORE 1 LINES

6
Downvote: Tại sao bạn đăng một cshcâu trả lời cho một bashcâu hỏi? Hai là hoàn toàn khác biệt và không tương thích.
tripleee
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.