sed: วิธีเปลี่ยน line ถ้าพบหรือต่อท้ายไฟล์ถ้าไม่พบ?


34

ด้วยอินพุตไฟล์เดียวที่มีความคิดเห็น (ขึ้นต้นด้วย #) และ VARIABLE = บรรทัดค่าเป็นไปได้ที่จะแทนที่ค่าสำหรับตัวแปรเดี่ยวหากพบและมิฉะนั้นต่อท้ายคู่ท้ายไฟล์ถ้าไม่พบ?

วิธีการปัจจุบันของฉันทำงานโดยการลบในรอบแรกจากนั้นต่อท้ายไฟล์ในรอบที่สอง แต่วิธีนี้ทำให้การเรียงลำดับบรรทัดยุ่งเหยิง (และเป็นสองคำสั่งต่างกัน):

sed -r "/^FOOBAR=.*$/d"      -i samefile &&
sed -r "$ a\FOOBAR=newvalue" -i samefile

อย่างไรก็ตามมีให้ทำเช่นนี้คือ รักษาคำสั่งซื้อในบรรทัด sed เดียวหรือไม่ หากยูทิลิตี้อื่น (awk, ... ) ทำสิ่งนี้ฉันจะพามันไปนอน

คำตอบ:


29

อันที่จริงมันค่อนข้างง่ายด้วยsed: ถ้าเส้นตรงเพียงแค่คัดลอกไปยังhพื้นที่เก่าแล้วsนำค่ามาประกอบ
ใน$บรรทัดla xเปลี่ยนพื้นที่ถือและพื้นที่รูปแบบจากนั้นตรวจสอบว่าหลังว่างเปล่า หากยังไม่ว่างก็หมายความว่าการทดแทนนั้นไม่ได้ทำอะไรเลย หากว่างเปล่านั่นหมายความว่าไม่พบการจับคู่ดังนั้นแทนที่พื้นที่รูปแบบด้วยค่า = ตัวแปรที่ต้องการจากนั้นต่อท้ายบรรทัดปัจจุบันในบัฟเฟอร์พัก ในที่สุดก็xเปลี่ยนอีกครั้ง:

sed '/^FOOBAR=/{h;s/=.*/=newvalue/};${x;/^$/{s//FOOBAR=newvalue/;H};x}' infile

ข้างต้นเป็นgnu sedไวยากรณ์ พกพา:

sed '/^FOOBAR=/{
h
s/=.*/=newvalue/
}
${
x
/^$/{
s//FOOBAR=newvalue/
H
}
x
}' infile

1
จะมีลักษณะเช่นnewvalueนี้หากเก็บไว้ในตัวแปรอย่างไร
user1810087

sed "/^${varName}=/{h;s/=.*/=${varValue}/};\${x;/^$/{s//${varName}=${varValue}/;H};x}" ${VARFILE}ด้วยตัวแปรอัญประกาศคู่เพื่ออนุญาตให้มีการทดแทนตัวแปรและการหลบหนี$ที่ไม่ใช่การแทนที่ ณ จุดนี้นอกจากนี้หากคุณเก็บค่าไว้ใน$$varName:sed "/^${varName}=/{h;s/=.*/=${!varName}/};\${x;/^$/{s//${varName}=${!varName}/;H};x}" ${VARFILE}
DarkMukke

1
วิธีการแก้ปัญหานี้ไม่ใช่เรื่องง่าย แต่มันได้ผล หน้าคนเกลี้ยกล่อมไม่ใช่สิ่งที่ง่ายที่สุดในการลอดผ่านมันจะมีประโยชน์มากถ้าคุณสามารถดูรายละเอียดผลกระทบของการแสดงออกในทุกส่วน :)
user2066480

18

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

grep -q "^FOOBAR=" file && sed "s/^FOOBAR=.*/FOOBAR=newvalue/" -i file || 
    sed "$ a\FOOBAR=newvalue" -i file

13

นี่เป็นsedวิธีที่ง่ายกว่าเพราะฉันไม่สามารถsed hold spaceใช้งานได้ง่าย หากคุณพอใจกับการhold spaceใช้วิธีการ don_crissti ให้โอกาสเพิ่มเติมในการรักษาทุกอย่างจากบรรทัดที่มีอยู่ แต่โดยปกติจะหายากมาก

ในวิธีการนี้คุณเพียงพิมพ์ทั้งหมดยกเว้นบรรทัดที่คุณต้องการวางจากนั้นในตอนท้ายให้เพิ่มการแทนที่

sed -n -e '/^FOOBAR=/!p' -e '$aFOOBAR=newvalue' infile

1
รุ่นนี้ดีมากหากคุณวางแผนที่จะอัพเดทไฟล์ที่อาจมีค่าอยู่ แต่ล้าสมัย
guillem

3

ตามคำตอบอื่น ๆ หากสิ่งที่คุณต้องการทำคือแทนที่ค่าของตัวแปรหากตัวแปรนั้นมีอยู่ในไฟล์และต่อท้ายไฟล์หากไม่มี (ซึ่งไม่ใช่sedคำสั่งที่คุณโพสต์) ลองได้:

perl -ne '$c=1 if s/^FOOBAR=.*$/FOOBAR=newvalue/;  
             print; 
             END{print "FOBAR=newvalue" unless $c==1}' file > tmpfile && 
mv tmpfile file

1

ง่ายขึ้นเล็กน้อยใน awk แม้ว่า "การแก้ไขสถานที่" จะไม่อัตโนมัติ:

awk -v varname="FOOBAR" -v newval="newvalue" '
    BEGIN {FS = OFS = "="}
    $1 == varname {$2 = newval; found = 1}
    {print}
    END {if (! found) {print varname, newval}}
' file > tempfile &&
mv tempfile file

1

เพียงใช้grepและechoสร้างระเบียนเปล่า:

grep -q '^FOOBAR=' somefile || echo 'FOOBAR=VALUE' >> somefile
sed -i 's/FOOBAR=.*$/FOOBAR=VALUE/' somefile 

แต่ละบรรทัดหนีออกมาพร้อมรหัสศูนย์ข้อผิดพลาด


คุณสูญเสียการสั่งซื้อทางไลน์ในขณะที่เพิ่มคำสั่งพิเศษgrepและecho
BlakBat

แน่นอนถ้าคุณแทรกรายการใหม่ในตอนท้ายของไฟล์ แต่ให้สั่งถ้าคุณแทนที่ค่าเก่า
MUY เบลเยี่ยม

0

ใช้งานได้จริงกับสิ่งต่อไปนี้: sed -i '/^FOOBAR=/{h;s/=.*/=newvalue/};${x;/^$/{s//FOOBAR=newvalue/;H};x}' infile ในคำตอบที่เลือก -i หายไป


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

-1

ทำเช่นนี้กับ Perl และในสถานที่นี้ทำงานได้ดีสำหรับฉัน:

grep ^FOOBAR= my.file && perl -i -ple "s/^FOOBAR=.+/FOOBAR=newvalue/g" my.file || echo FOOBAR=newvalue >> my.file

2
คำตอบนี้ไม่ดีในหลาย ๆ ด้าน! grepและechoและperlแทนการทำทุกอย่างในperl? นอกจากนี้การเขียนไปยังไฟล์ ( >> my.file) ตามที่คุณอ่านจากมัน ( grep my.file)?
vladr
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.