เชลล์สคริปต์ - ลบอัญประกาศแรกและสุดท้าย (") ออกจากตัวแปร


225

ด้านล่างนี้เป็นตัวอย่างของเชลล์สคริปต์จากสคริปต์ที่ใหญ่กว่า มันลบคำพูดจากสตริงที่ถือโดยตัวแปร ฉันกำลังใช้ sed แต่มีประสิทธิภาพหรือไม่ ถ้าไม่เช่นนั้นวิธีที่มีประสิทธิภาพคืออะไร?

#!/bin/sh

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

sed "s/^\(\"\)\(.*\)\1\$/\2/g" <<<"$opt"ผมขอแนะนำให้ใช้ ไวยากรณ์นี้จะลบ qoutes เฉพาะเมื่อมีคู่ที่ตรงกัน
John Smith

@JohnSmith ฉันต้องหลีกเลี่ยงอัญประกาศโดยอัตโนมัติในเชลล์สคริปต์ แต่ฉันต้องทำเช่นนั้นไม่ว่าจะตรงกันหรือไม่ดังนั้นฉันอาจจะไม่ใช้นิพจน์ที่คุณโพสต์
Pysis

หากคุณพบว่าคำถามนี้ในขณะที่เพียงต้องการที่จะลบคำพูดทั้งหมดดูคำตอบนี้: askubuntu.com/a/979964/103498
Gordon Bean

คำตอบ:


268

มีวิธีที่ง่ายและมีประสิทธิภาพมากขึ้นโดยใช้คุณลักษณะการลบคำนำหน้า / คำต่อท้ายเชลล์แบบเนทีฟ:

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

${opt%\"}จะลบคำต่อท้าย"(หนีด้วยแบ็กสแลชเพื่อป้องกันการตีความเชลล์)

${temp#\"}จะลบคำนำหน้า"(หนีด้วยแบ็กสแลชเพื่อป้องกันการตีความเชลล์)

ข้อดีอีกอย่างคือมันจะลบเครื่องหมายคำพูดล้อมรอบเฉพาะในกรณีที่มีเครื่องหมายคำพูดล้อมรอบอยู่

BTW โซลูชันของคุณจะลบอักขระตัวแรกและตัวสุดท้ายเสมอไม่ว่าพวกเขาจะเป็นใคร (แน่นอนฉันแน่ใจว่าคุณรู้ข้อมูลของคุณ

ใช้ sed:

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

(รุ่นที่ปรับปรุงแล้วตามที่ระบุโดย jfgagne กำจัดเสียงก้อง)

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

ดังนั้นจึงแทนที่ผู้นำ"ด้วยไม่มีอะไรและต่อท้าย"ด้วยไม่มีอะไรเกินไป ในการเรียกใช้งานเดียวกัน (ไม่จำเป็นต้องไพพ์และเริ่มการทำงานอื่นอีกการใช้-eคุณสามารถมีการประมวลผลข้อความหลายรายการ)


14
คุณสามารถกำจัดของท่อในการแก้ปัญหา sed sed -e 's/^"//' -e 's/"$//' <<< $optกับ
jfg956

1
สิ่งนี้อาจทำให้เกิดความผิดพลาดได้สตริงไม่ได้มีทั้งตัวละครที่นำหน้าและต่อท้าย ข้อเสนอแนะใด ๆ สำหรับการจัดการที่งดงาม?
jsears

หากต้องการจัดการเครื่องหมายคำพูดด้านนอกที่จับคู่เท่านั้นให้ดูคำตอบโดย @Joachim Pileborg
jsears

1
@jsears Huh? สิ่งนี้จะจดจ้องอย่างใดอย่างหนึ่งจากจุดเริ่มต้นหากมีหนึ่งและหนึ่งจากจุดสิ้นสุดถ้ามี หากคุณไม่ต้องการลบเว้นแต่จะมีทั้งคู่ ใช่sedสามารถใช้ regex เดียวหรือการแทนที่ตัวแปรสามารถห่อในบรรทัดบรรทัดcase $opt in '"'*'"') ... do it ... ;; esac
tripleee

2
คุณสามารถหลีกเลี่ยงนิพจน์หลาย ๆ ตัวได้โดยใช้sed 's/^"\|"$//g'
tzrlk

287

ใช้trเพื่อลบ":

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

หมายเหตุ : สิ่งนี้จะลบเครื่องหมายคำพูดคู่ทั้งหมดไม่เพียง แต่นำหน้าและต่อท้าย


16
นี่ไม่ใช่สิ่งที่ OP ร้องขอเพราะมันยังลบเครื่องหมายคำพูดทั้งหมดไม่เพียง แต่นำหน้าและต่อท้าย
Lenar Hoyt

19
แม้ว่าจะไม่ตอบ OP อย่างชัดเจนนี่เป็นการแก้ปัญหาสำหรับฉันเพราะมีเพียงอัญประกาศคู่ที่จุดเริ่มต้นและจุดสิ้นสุดของ "/ path / file-name" ไม่มีเครื่องหมายคำพูดคู่ฝังอยู่ +1
WinEunuuchs2Unix

6
โซลูชันนี้จะเป็นสิ่งที่ผู้คนจำนวนมากต้องการ ในหลายกรณีการเขียนสคริปต์สามารถทำให้ข้อมูลที่ใช้งานได้ง่ายลงไปยังสตริงที่ล้อมรอบด้วยเครื่องหมายคำพูด
Shadoninja

2
สง่างามและบันทึกฉันจากเวลาทดลองใช้ข้อผิดพลาดการดีบัก ขอบคุณ.
Scott Wade

นี่คือสิ่งที่เราต้องการและทำไมจึงมีคะแนนเสียงมากกว่าคำตอบที่ยอมรับ
apurvc

38

นี่จะเป็นการลบเครื่องหมายคำพูดคู่ทั้งหมด

echo "${opt//\"}"

1
Don't remove this \" quoteแต่จะทำลายด้วยคำพูดหนีเช่น :-(
gniourf_gniourf

นี่เป็นส่วนขยาย Bash ดังนั้นจึงไม่สามารถใช้ได้กับเชลล์สคริปต์โดยทั่วไป (คำถามนี้คลุมเครือว่าสิ่งนี้สำคัญหรือไม่ผู้เข้าชมที่พบสิ่งนี้ใน Google อาจกำลังมองหาโซลูชัน POSIX)
tripleee

ความสมบูรณ์แบบ! สิ่งที่ฉันต้องการ ฉันรักคำถามเช่นนี้ที่ให้คำตอบมากมายแก่คุณไม่ใช่แค่สิ่งที่ OP ต้องการ อัญมณีอยู่ในคำตอบที่ไม่ได้รับการยอมรับ!
dlite922

ฉันกลัวว่า OP ต้องการบางสิ่งที่ลบเฉพาะคำพูดนำ / คำต่อท้ายเท่านั้น
Fernando Paz

36

มีวิธีที่ตรงไปตรงมาโดยใช้xargs :

> echo '"quoted"' | xargs
quoted

xargsใช้ echo เป็นคำสั่งเริ่มต้นหากไม่มีคำสั่งและแถบคำพูดจากอินพุต ดูเช่นที่นี่


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

1
สิ่งนี้ใช้ได้ แต่สำหรับจำนวนอัญประกาศเท่านั้นในสตริง หากมีตัวเลขคี่มันจะสร้างข้อผิดพลาด
James Shewey


19

วิธีที่สั้นที่สุด - ลอง:

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

มันจะลบ"s (เครื่องหมายคำพูดคู่) ทั้งหมดออกจากopt(จะมีการเสนอราคาสองเท่าอื่น ๆ นอกเหนือจากในตอนต้นและตอนท้ายใช่หรือไม่ดังนั้นมันจึงเป็นสิ่งเดียวกันจริง ๆ และสั้นกว่า ;-))


4
ถ้าคุณต้องการที่จะลบเครื่องหมายคำพูดคู่ทั้งหมดมันจะดีกว่าถ้าใช้: "$ {opt // \" /} "ไม่มีไพพ์, ไม่มีเชลล์ย่อย ... และระวังว่าถ้าคุณมีช่องว่างในอ็อปเอาท์คุณอาจหลวม พวกเขาอ้างตัวแปรเช่น: echo "$ opt"
เสมอ

ตัวแปรโดยทั่วไปจะอ่านเส้นทางของ DocumentRoot จากไฟล์ปรับแต่ง httpd ของดังนั้นฉันไม่คิดว่าจะมีกรณีที่ตัวอักษรพูดอาจจะมีในสตริง และสิ่งนี้เป็นสิ่งที่ดีและมีประสิทธิภาพมาก .... ขอบคุณ!
user1263746

16

หากคุณกำลังใช้ jq และพยายามลบคำพูดออกจากผลลัพธ์คำตอบอื่น ๆ จะใช้ได้ แต่ก็มีวิธีที่ดีกว่า โดยใช้-rตัวเลือกคุณสามารถส่งออกผลลัพธ์โดยไม่มีเครื่องหมายคำพูด

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

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

ฉันใช้jqแต่โปรดทราบว่ามันไม่ทำงานถ้า jq ยังเอาท์พุท ASCII ด้วย-a(มันเป็นข้อผิดพลาดที่ด้านข้างของ
jq

yqนอกจากนี้ยังมี-rตัวเลือก:yq -r '.foo' file.yml
Hlib Babii

12

ปรับปรุง

คำตอบที่ง่ายและสง่างามจากการแยกคำพูดเดี่ยวและคู่ในสตริงโดยใช้คำสั่ง bash / Linux มาตรฐานเท่านั้น :

BAR=$(eval echo $BAR)BARแถบคำพูดจาก

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

จากคำตอบของ hueybois ฉันมาพร้อมกับฟังก์ชั่นนี้หลังจากการลองผิดลองถูกมาก:

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

หากคุณไม่ต้องการอะไรที่พิมพ์ออกมาคุณสามารถไพพ์ evals ได้ /dev/null 2>&1ได้

การใช้งาน:

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

1
แม้ว่าฉันจะชอบความเรียบง่ายและสง่างามจริงๆฉันคิดว่ามันคุ้มค่าที่จะสังเกตว่า Eval ไม่ได้ทำแค่การตัดคำพูดสองเท่า แต่จริงๆแล้วประเมินว่าเป็นบรรทัดของโค้ด ดังนั้นเทคนิคนี้อาจให้ผลลัพธ์ที่ไม่คาดคิดเมื่อ BAR มีลำดับอื่น ๆ ที่อาจแทนที่ด้วยเชลล์ (เช่น BAR = \ 'abc \' หรือ BAR = ab \ 'c หรือ BAR = a \ $ b หรือ BAR = a \ $ (ls *))
MaxP

11

ทางออกที่ง่ายที่สุดใน Bash:

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

สิ่งนี้เรียกว่าการขยายซับสตริง (ดูGnu Bash Manualและค้นหา${parameter:offset:length}) ในตัวอย่างนี้ใช้สตริงย่อยจากการsเริ่มต้นที่ตำแหน่ง 1 และสิ้นสุดที่ตำแหน่งสุดท้ายที่สอง เพราะนี่คือความจริงที่ว่าถ้าเป็นค่าลบมันถูกตีความว่าเป็นถอยหลังทำงานชดเชยจากการสิ้นสุดของlengthparameter


ความยาวติดลบรองรับจาก bash v4.2
mr.spuratic

8

นี่เป็นวิธีที่ไม่ต่อเนื่องที่สุดโดยไม่ใช้ sed:

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

หรือ

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

เอาท์พุท:

   quotes: "fish"
no quotes:  fish

ผมได้รับนี้จากแหล่งที่มา


การดำเนินการนี้จะลบเครื่องหมายคำพูดจากภายในสตริงรวมถึงคำที่อยู่รอบ ๆ
jsears

นอกเหนือจากความเห็นนี้เป็นเหมือน@ คำตอบของ StevenPenny จาก 2012
tripleee


2

รุ่นของฉัน

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
}

ฟังก์ชั่นยอมรับชื่อตัวแปรและตัดเครื่องหมายคำพูดให้เข้าที่ มันจะตัดเฉพาะคู่ที่ตรงกันของคำพูดนำหน้าและต่อท้าย มันไม่ได้ตรวจสอบว่าคำพูดต่อท้ายหนีหรือไม่ (นำหน้าด้วย\ที่ไม่ได้หลบหนี)

จากประสบการณ์ของฉันฟังก์ชั่นยูทิลิตี้สตริงวัตถุประสงค์ทั่วไปเช่นนี้ (ฉันมีห้องสมุดของพวกเขา) มีประสิทธิภาพมากที่สุดเมื่อจัดการสตริงโดยตรงไม่ใช้การจับคู่รูปแบบใด ๆ และโดยเฉพาะอย่างยิ่งไม่สร้างเชลล์ย่อยใด ๆ หรือเรียกเครื่องมือภายนอกใด ๆ เช่นsed, หรือawkgrep

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

ฉันรู้ว่านี่เป็นคำถามที่เก่ามาก แต่นี่เป็นอีกรูปแบบหนึ่งที่อาจเป็นประโยชน์กับใครบางคน ไม่เหมือนกับคนอื่น ๆ บางคนมันเพียงแทนที่เครื่องหมายคำพูดสองครั้งที่เริ่มต้นหรือสิ้นสุด ...

echo "$opt" | sed -r 's/^"|"$//g'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.