ทำไมต้อง expr1 | sed expr2` ต่างจาก `sed -e expr1 -e expr2`


10

ฉันได้แยกเอาต์พุตจากidเพื่อจัดเตรียมรายการ line-by-list ที่สามารถอ่านได้มากขึ้นของกลุ่มที่ผู้ใช้เป็นสมาชิก:

id roaima | sed 's/,/\n\t/g'
uid=1001(roaima) gid=1001(roaima) groups=1001(roaima)
    24(cdrom)
    25(floppy)
    ...
    822413650 (international (uk) location)

ฉันต้องการแยกหมายเลขกลุ่มออกจากชื่อที่มีวงเล็บเหลี่ยมดังนั้นฉันจึงขยายการแสดงออกเช่นนี้

id roaima | sed -e 's/,/\n\t/g' -e '2,$s/(/ (/'

อย่างไรก็ตามสิ่งนี้ไม่ได้ทำตามที่ฉันคาดไว้ในตอนแรก การแสดงออกที่สองดูเหมือนจะไม่มีผลกระทบ

แต่เพื่อให้ได้ผลลัพธ์ที่ฉันต้องการฉันต้องรันสองsedคำสั่งแยกกันดังนี้:

id roaima | sed -e 's/,/\n\t/g' | sed '2,$s/(/ (/'
uid=1001(roaima) gid=1001(roaima) groups=1001(roaima)
    24 (cdrom)
    25 (floppy)
    ...
    822413650 (international (uk) location)

ทำไมฉันต้องมีสองsedคำสั่งในไพพ์แทนที่จะเป็นคำสั่งที่มีหลายคำสั่ง? หรือถ้าฉันสามารถทำได้ด้วยอันเดียวsedฉันจะทำยังไงดี?

สิ่งที่ฉันต้องการโดยเฉพาะอย่างยิ่งคือการมีช่องว่างเดียวระหว่างค่า UID / GID และชื่อที่อยู่ในวงเล็บของทุกรายการ (รวมถึง UID และ GID ในบรรทัดแรก) แต่ข้อแม้คือในข้อมูลจริงของฉันฉันสามารถมีกลุ่มได้ มีเครื่องหมายวงเล็บอยู่ในชื่อของพวกเขาและฉันไม่ต้องการชื่อที่ยุ่งเหยิง

คำตอบ:


14

sedชอบawkหรือcutหรือperl -neทำงานในแต่ละบรรทัดทีละบรรทัด

sed -e code1 -e code2

จริงๆแล้วทำงานเป็น:

while(patternspace = getline()) {
  linenumber++
  code1
  code2
} continue {print patternspace}

หาก code2 ของคุณคือ2,$ s/foo/bar/:

if (linenumber >= 2) sub(/foo/, "bar", patternspace)

เนื่องจากอินพุตของคุณมีเพียงหนึ่งบรรทัดsub()จะไม่มีการรัน

การแทรกอักขระบรรทัดใหม่ในพื้นที่รูปแบบcode1ไม่ทำให้linenumberเพิ่มขึ้น

คุณมีพื้นที่รูปแบบหนึ่งบรรทัดที่มีหลายบรรทัดในขณะที่ประมวลผลอินพุตบรรทัดแรกและบรรทัดเดียว หากคุณต้องการแก้ไขในบรรทัดที่สองและที่มากกว่าของพื้นที่รูปแบบหลายบรรทัดนั้นคุณต้องทำสิ่งต่อไปนี้:

s/\(\n[^(]*\)(/\1 (/g

แม้ว่าที่นี่แน่นอนคุณอาจดำเนินการสองอย่างในคราวเดียว:

id | sed 's/,\([^(]*\)(/\n\t\1 (/g'

awk และ perl -n / p ใช้งานได้กับแต่ละเรคคอร์ดซึ่งมีค่าเริ่มต้นเป็นบรรทัด แต่สามารถเปลี่ยนแปลงได้ ในกรณีนี้-vRS=,หรือ-054สามารถช่วยได้
dave_thompson_085

5

หากคุณมี GNU sed คุณสามารถใช้

id username | sed 's/(/ (/4g; s/,/\n\t/g'

ซึ่งจะเพิ่มช่องว่างก่อนเครื่องหมายวงเล็บเปิดที่ 4 และถัดมาจากนั้นแทนที่เครื่องหมายจุลภาค


1
นั่นดูน่าสนใจ น่าเสียดายที่มันมีผลกับชื่อกลุ่มที่มีวงเล็บเช่นตัวอย่างของฉันinternational (uk) locationโดยการแทรกช่องว่างที่ไม่ต้องการในชื่อตัวเอง
roaima

จากนั้นใช้s/\([[:digit:]]\+\)(/\1 (/4gซึ่งจะเพิ่มช่องว่างเฉพาะถ้ามีตัวเลขก่อนหน้าวงเล็บ
เกล็นแจ็

1

สิ่งที่ @ stéphane-chazelas พูดว่าเป็นความจริง แต่คุณสามารถเพิ่มช่องว่างก่อนและแยกเป็นบรรทัดหลังจากนี้:

sed -e 's:\([,=][0-9]*\):\1 :g' -e 's:,:\n\t:g'

หรือในสคริปต์ตัวเดียว (ไม่มี-e):

sed 's:\([,=][0-9]*\):\1 :g; s:,:\n\t:g'

โดยปกติเราใช้ " /" เป็นตัวคั่นของการค้นหาคำสั่ง แต่ก็ยอมรับอักขระใด ๆ ได้เช่นกันดังนั้นบางครั้งมันก็ง่ายต่อการอ่านโดยใช้อักขระอื่นเช่น " :" เพื่อหลีกเลี่ยงการรวมกันเช่น " /\"

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