Shell script - xóa trích dẫn đầu tiên và cuối cùng (") khỏi một biến


225

Dưới đây là đoạn mã của một tập lệnh shell từ một tập lệnh lớn hơn. Nó loại bỏ các trích dẫn từ chuỗi được giữ bởi một biến. Tôi đang làm nó bằng cách sử dụng sed, nhưng nó có hiệu quả không? Nếu không thì cách hiệu quả là gì?

#!/bin/sh

opt="\"html\\test\\\""
temp=`echo $opt | sed 's/.\(.*\)/\1/' | sed 's/\(.*\)./\1/'`
echo $temp

Tôi sẽ đề nghị sử dụng sed "s/^\(\"\)\(.*\)\1\$/\2/g" <<<"$opt". Cú pháp này sẽ loại bỏ qoutes chỉ khi có một cặp phù hợp.
John Smith

@JohnSmith Tôi cũng phải tự động thoát các trích dẫn trong tập lệnh shell, nhưng tôi cần làm như vậy cho dù chúng có khớp hay không, vì vậy tôi có thể sẽ không sử dụng biểu thức mà bạn đã đăng.
Pysis

Nếu bạn tìm thấy câu hỏi này trong khi chỉ muốn xóa tất cả các trích dẫn, hãy xem câu trả lời này: askubfox.com/a/979964/103498 .
Gordon Bean

Câu trả lời:


268

Có một cách đơn giản và hiệu quả hơn, bằng cách sử dụng tính năng loại bỏ tiền tố / hậu tố gốc:

temp="${opt%\"}"
temp="${temp#\"}"
echo "$temp"

${opt%\"}sẽ loại bỏ hậu tố "(thoát với dấu gạch chéo ngược để ngăn việc giải thích shell).

${temp#\"}sẽ loại bỏ tiền tố "(thoát bằng dấu gạch chéo ngược để ngăn việc giải thích shell).

Một ưu điểm khác là nó sẽ loại bỏ các trích dẫn xung quanh chỉ khi có các trích dẫn xung quanh.

BTW, giải pháp của bạn luôn loại bỏ ký tự đầu tiên và cuối cùng, bất kể chúng là gì (tất nhiên, tôi chắc chắn bạn biết dữ liệu của mình, nhưng tốt hơn là luôn chắc chắn về những gì bạn đang xóa).

Sử dụng sed:

echo "$opt" | sed -e 's/^"//' -e 's/"$//'

(Phiên bản cải tiến, như được chỉ định bởi jfgagne, loại bỏ tiếng vang)

sed -e 's/^"//' -e 's/"$//' <<<"$opt"

Vì vậy, nó thay thế một dẫn đầu "không có gì, và một dấu vết "không có gì quá. Trong cùng một lời gọi (không cần phải đặt ống và bắt đầu một sed khác. Sử dụng -ebạn có thể xử lý nhiều văn bản).


14
Bạn có thể thoát khỏi đường ống trong giải pháp sed với sed -e 's/^"//' -e 's/"$//' <<< $opt.
jfg956 17/03/2016

1
Điều này có thể làm sai nó chuỗi không có cả một ký tự trích dẫn hàng đầu và dấu. Bất kỳ đề nghị để xử lý mà duyên dáng?
jsears

Để chỉ xử lý các trích dẫn bên ngoài phù hợp, hãy xem câu trả lời của @Joachim Pileborg
jsears

1
@jsears Hả? Điều này đặc biệt cắt một từ đầu nếu có một, và một từ cuối nếu có. Nếu bạn không muốn xóa trừ khi cả hai đều có mặt; có, một sedregex duy nhất có thể được sử dụng hoặc thay thế biến đổi có thể được gói trong một dòng nào đócase $opt in '"'*'"') ... do it ... ;; esac
tripleee 7/10/2016

2
Bạn có thể tránh nhiều biểu thức bằng cách sử dụngsed 's/^"\|"$//g'
tzrlk

287

Sử dụng tr để xóa ":

 echo "$opt" | tr -d '"'

Lưu ý : Điều này loại bỏ tất cả các dấu ngoặc kép, không chỉ dẫn và theo dõi.


16
Đây không phải là những gì OP yêu cầu vì nó cũng loại bỏ tất cả các trích dẫn, không chỉ các trích dẫn hàng đầu và dấu.
Lenar Hoyt

19
Mặc dù không trả lời OP một cách rõ ràng nhưng điều này giải quyết cho tôi vì chỉ có hai dấu ngoặc kép ở đầu và cuối của "/ path / tên tệp". Không có dấu ngoặc kép nhúng. +1
WinEunuuchs2Unix

6
Giải pháp này sẽ là điều mà rất nhiều người muốn. Trong nhiều trường hợp, kịch bản có thể dễ dàng đưa dữ liệu khả thi xuống một chuỗi được bao quanh bởi dấu ngoặc kép.
Shadoninja

2
Thanh lịch và cứu tôi khỏi thời gian gỡ lỗi thử nghiệm nhiều hơn. Cám ơn.
Scott Wade

Đây là những gì lý tưởng người ta muốn và đó là lý do tại sao nó có nhiều phiếu hơn câu trả lời được chấp nhận.
apurvc

38

Điều này sẽ loại bỏ tất cả các dấu ngoặc kép.

echo "${opt//\"}"

1
Nhưng sẽ phá vỡ với dấu ngoặc kép thoát, ví dụ , Don't remove this \" quote. :-(
gniourf_gniourf

Đây là một phần mở rộng Bash, vì vậy không áp dụng cho shell script nói chung. (Câu hỏi mơ hồ là liệu điều này có quan trọng hay không. Khách truy cập tìm thấy điều này trong Google có thể đang tìm kiếm một giải pháp POSIX.)
tripleee 7/10/2016

Sự hoàn hảo! Chính xác những gì tôi cần. Tôi thích những câu hỏi như thế này cung cấp cho bạn rất nhiều câu trả lời, không chỉ những gì OP yêu cầu. Những viên đá quý nằm trong câu trả lời không được chấp nhận!
dlite922

Tôi sợ OP muốn một cái gì đó chỉ loại bỏ các trích dẫn hàng đầu / dấu và giữ cho các dấu thoát.
Fernando Paz

36

Có một cách đơn giản bằng xargs :

> echo '"quoted"' | xargs
quoted

xargs sử dụng echo làm lệnh mặc định nếu không có lệnh nào được cung cấp và loại bỏ dấu ngoặc kép khỏi đầu vào. Xem ví dụ ở đây .


echo '"quoted"' | xargs -> quoted
kyb

1
Điều này hoạt động, nhưng chỉ cho một số lượng trích dẫn chẵn trong một chuỗi. Nếu có một số lẻ, nó sẽ tạo ra một lỗi.
James Shewey


19

Cách ngắn nhất - thử:

echo $opt | sed "s/\"//g"

Nó thực sự loại bỏ tất cả "(dấu ngoặc kép) khỏi opt(thực sự sẽ có thêm bất kỳ dấu ngoặc kép nào khác ngoài phần đầu và phần cuối không? Vì vậy, nó thực sự giống nhau, và ngắn gọn hơn nhiều ;-))


4
Nếu bạn muốn xóa tất cả các dấu ngoặc kép, thì tốt hơn hết là sử dụng: "$ {opt // \" /} ". Không có ống dẫn, không có phần phụ ... Và hãy cẩn thận nếu bạn có khoảng trắng trong opt, bạn có thể mất Chúng. Luôn trích dẫn các biến như: echo "$ opt"
huelbois

Chà, về cơ bản, biến này đọc đường dẫn của DocumentRoot từ tệp cấu hình của httpd, vì vậy tôi không nghĩ có thể có trường hợp một ký tự trích dẫn có thể có trong chuỗi. Và chiếc sed này gọn gàng và hiệu quả hơn nhiều .... Cảm ơn!
1263746

16

Nếu bạn đang sử dụng jq và cố gắng loại bỏ các trích dẫn khỏi kết quả, các câu trả lời khác sẽ hoạt động, nhưng có một cách tốt hơn. Bằng cách sử dụng -rtùy chọn, bạn có thể xuất kết quả mà không có dấu ngoặc kép.

$ echo '{"foo": "bar"}' | jq '.foo'
"bar"

$ echo '{"foo": "bar"}' | jq -r '.foo'
bar

Tôi đang sử dụng jqnhưng xin lưu ý rằng nó không hoạt động nếu jq cũng xuất ra đầu ra ASCII với -a(đó là lỗi ở phía jq)
Poyrazoğlu có thể

yqcũng có -rtùy chọn:yq -r '.foo' file.yml
Hlib Babii

12

Cập nhật

Một câu trả lời đơn giản và thanh lịch từ Tước các trích dẫn đơn và kép trong một chuỗi chỉ sử dụng các lệnh bash / tiêu chuẩn Linux :

BAR=$(eval echo $BAR)dải trích dẫn từ BAR.

================================================== ===========

Dựa trên câu trả lời của hueybois, tôi đã tìm ra chức năng này sau nhiều thử nghiệm và lỗi:

function stripStartAndEndQuotes {
    cmd="temp=\${$1%\\\"}"
    eval echo $cmd
    temp="${temp#\"}"
    eval echo "$1=$temp"
}

Nếu bạn không muốn bất cứ điều gì được in ra, bạn có thể dẫn các evals đến /dev/null 2>&1.

Sử dụng:

$ BAR="FOO BAR"
$ echo BAR
"FOO BAR"
$ stripStartAndEndQuotes "BAR"
$ echo BAR
FOO BAR

1
Mặc dù tôi thực sự thích sự đơn giản và thanh lịch, tôi nghĩ rằng đáng chú ý là eval không chỉ thực hiện hai lần trích dẫn, mà thực sự đánh giá là một dòng mã. Do đó, kỹ thuật này có thể mang lại kết quả không mong muốn khi BAR chứa các chuỗi khác có thể thay thế bằng vỏ (ví dụ: BAR = \ 'abc \' hoặc BAR = ab \ 'c hoặc BAR = a \ $ b hoặc BAR = a \ $ (ls *))
MaxP

11

Giải pháp đơn giản nhất trong Bash:

$ s='"abc"'
$ echo $s
"abc"
$ echo "${s:1:-1}"
abc

Đây được gọi là mở rộng chuỗi con (xem Hướng dẫn sử dụng Gnu Bash và tìm kiếm ${parameter:offset:length}). Trong ví dụ này, nó lấy chuỗi con sbắt đầu từ vị trí 1 và kết thúc ở vị trí cuối cùng thứ hai. Điều này là do thực tế là nếu lengthlà một giá trị âm, nó được hiểu là phần bù chạy ngược từ cuối parameter.


độ dài âm được hỗ trợ từ bash v4.2
mr.spuratic

8

Đây là cách riêng biệt nhất mà không sử dụng sed:

x='"fish"'
printf "   quotes: %s\nno quotes:  %s\n" "$x" "${x//\"/}"

Hoặc là

echo $x
echo ${x//\"/}

Đầu ra:

   quotes: "fish"
no quotes:  fish

Tôi đã nhận được điều này từ một nguồn .


Điều này sẽ loại bỏ các trích dẫn từ bên trong chuỗi cũng như những người xung quanh nó.
jsears

Ngoài phần bình luận, nó giống hệt với câu trả lời của @ StevenPenny từ năm 2012 .
tripleee

3

Có một cách khác để làm điều đó. Giống:

echo ${opt:1:-1}

2

Phiên bản của tôi

strip_quotes() {
    while [[ $# -gt 0 ]]; do
        local value=${!1}
        local len=${#value}
        [[ ${value:0:1} == \" && ${value:$len-1:1} == \" ]] && declare -g $1="${value:1:$len-2}"
        shift
    done
}

Hàm chấp nhận (các) tên biến và dải trích dẫn tại chỗ. Nó chỉ dải một cặp kết hợp của dấu ngoặc kép hàng đầu và dấu. Nó không kiểm tra xem dấu ngoặc kép có được thoát hay không (trước \đó không phải là dấu thoát).

Theo kinh nghiệm của tôi, các hàm tiện ích chuỗi đa năng như thế này (tôi có thư viện của chúng) hiệu quả nhất khi thao tác trực tiếp với chuỗi, không sử dụng bất kỳ khớp mẫu nào và đặc biệt là không tạo bất kỳ shell phụ nào, hoặc gọi bất kỳ công cụ bên ngoài nào như sed, awkhoặc grep.

var1="\"test \\ \" end \""
var2=test
var3=\"test
var4=test\"
echo before:
for i in var{1,2,3,4}; do
    echo $i="${!i}"
done
strip_quotes var{1,2,3,4}
echo
echo after:
for i in var{1,2,3,4}; do
    echo $i="${!i}"
done

0

Tôi biết đây là một câu hỏi rất cũ, nhưng đây là một biến thể sed khác, có thể hữu ích cho ai đó. Không giống như một số khác, nó chỉ thay thế dấu ngoặc kép ở đầu hoặc cuối ...

echo "$opt" | sed -r 's/^"|"$//g'
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.