แทนที่ทั้งบรรทัดที่มีสตริงโดยใช้ Sed


319

ฉันมีไฟล์ข้อความที่มีบรรทัดคล้าย ๆ

sometext sometext sometext TEXT_TO_BE_REPLACED sometext sometext sometext

ฉันต้องการแทนที่ทั้งบรรทัดด้านบนด้วย

This line is removed by the admin.

คำค้นหาคือ TEXT_TO_BE_REPLACED

ฉันต้องเขียนเชลล์สคริปต์สำหรับสิ่งนี้ ฉันจะใช้สิ่งนี้ได้sedอย่างไร


@Scharron ฉันลอง sed -rne 's / (TEXT_TO_BE_REPLACED) \ s + \ w + / \ 1 yyy / xxx' แต่นั่นจะแทนที่ yyy ด้วย xxx ในสตริงถ้า yyy ใด ๆ ปรากฏอยู่ ในกรณีของฉันข้อความไม่ได้รับการแก้ไข ... ทั้งหมดที่ฉันมีคือ TEXT_TO_BE_REPLACED
ราหุล

นั่นไม่ใช่การแสดงออกที่ถูกต้อง คุณแน่ใจหรือไม่ว่าคุณต้องการมันด้วย sed ภาษาการเขียนโปรแกรมใด ๆ ที่มี regexps ที่ดีสามารถทำการแทนที่คุณได้ (ค้นหาฟังก์ชันย่อย) นั่นจะง่ายกว่าการเข้าใจตัวเอง
Scharron

@Schron ดีทำมันด้วยเชลล์สคริปต์ดังนั้นฉันเดา sed เป็นทางออกที่ดีที่สุดของฉัน
ราหุล

คำตอบ:


483

คุณสามารถใช้คำสั่งเปลี่ยนแปลงเพื่อแทนที่ทั้งบรรทัดและ-iตั้งค่าสถานะเพื่อทำการเปลี่ยนแปลงในสถานที่ ตัวอย่างเช่นการใช้ GNU sed:

sed -i '/TEXT_TO_BE_REPLACED/c\This line is removed by the admin.' /tmp/foo

4
โปรดทราบว่าคุณต้องการพื้นที่ว่างก่อน c \ ฉันเพิ่งแก้ไขเพื่อเพิ่มสิ่งนี้
Marcus Downing

27
@ MarcusDowning GNU sed ไม่ต้องการพื้นที่ มันทำงานได้ดีตามที่โพสต์เดิม หาก sed โดยเฉพาะของคุณต้องการพื้นที่แล้วโดยทั้งหมดทราบว่า sed ใดที่เข้ากันไม่ได้และเพิ่มการร้องขอที่จำเป็นเป็นความคิดเห็น อย่างไรก็ตามโปรดอย่าเปลี่ยนรหัสการทำงานในคำตอบที่ยอมรับได้
Todd A. Jacobs

7
ฉันจะใช้ตัวแปรแทนข้อความ "This ... " ได้อย่างไร ถ้าฉันแทนที่ด้วยตัวแปร $ จะไม่พิมพ์เนื้อหา แต่เป็นชื่อตัวแปร
Steven

18
มีปัญหาc\ เมื่อตามด้วยตัวแปรโดยตรง: …c\$VAR…แบ็กสแลชจะหนีเงินดอลลาร์ ในกรณีนี้ฉัน (bash / sed บน Ubuntu 15.10) ต้องเขียน…c\\$VAR…
Jan

6
ในการใช้งาน Mac: sed -i '' '/TEXT_TO_BE_REPLACED/c\This line is removed by the admin.' /tmp/foo; (เมื่อพารามิเตอร์แรกว่างเปล่าจะทำการแก้ไขในไฟล์หรือสร้างการสำรองข้อมูล)
AndreDurao

152

คุณต้องใช้ wildards ( .*) ก่อนและหลังเพื่อแทนที่ทั้งบรรทัด:

sed 's/.*TEXT_TO_BE_REPLACED.*/This line is removed by the admin./'

ขอขอบคุณทำงานของฉัน: sed 's /.* <expression>. * / <expression> SE_LABEL = ABC <expression> / g' MYR2.xml> test.txt
Nasri Najib

9
สิ่งนี้ใช้งานได้กับ Mac OS X Yosemite โดยมีข้อยกเว้นว่าฉันใช้แฟล็ก -i และ -e ดังนี้:sed -i -e "s/.*search_string.*/Replacement_line/' file_being_searched.txt
Kent Bull

1
@ KentJohnson ฉันคิดว่าคุณมีเครื่องหมายคำพูดไม่ตรงกันในคำสั่งของคุณ
HashHazard

@ MBarnett คุณพูดถูกฉันควรจะใส่เครื่องหมายคำพูดสองตัวที่นั่น
Kent Bull

2
เพียงเพื่อข้อมูลเต็ม เพื่อให้มันเข้ามาแทนที่หนึ่งสามารถเพิ่ม-iตัวเลือก
Temak

20

คำตอบที่ยอมรับไม่ได้สำหรับฉันด้วยเหตุผลหลายประการ:

  • รุ่น sed ของฉันไม่เหมือนกับ-iส่วนขยายที่มีความยาวเป็นศูนย์
  • ไวยากรณ์ของc\คำสั่งแปลกและฉันไม่สามารถใช้งานได้
  • ฉันไม่ได้ตระหนักถึงปัญหาบางอย่างของฉันมาจากเครื่องหมายทับ

ดังนั้นนี่คือวิธีแก้ไขปัญหาที่ฉันคิดว่าควรจะได้ผลในกรณีส่วนใหญ่:

function escape_slashes {
    sed 's/\//\\\//g' 
}

function change_line {
    local OLD_LINE_PATTERN=$1; shift
    local NEW_LINE=$1; shift
    local FILE=$1

    local NEW=$(echo "${NEW_LINE}" | escape_slashes)
    sed -i .bak '/'"${OLD_LINE_PATTERN}"'/s/.*/'"${NEW}"'/' "${FILE}"
    mv "${FILE}.bak" /tmp/
}

ดังนั้นการใช้ตัวอย่างเพื่อแก้ไขปัญหาที่เกิดขึ้น:

change_line "TEXT_TO_BE_REPLACED" "This line is removed by the admin." yourFile

18

คำตอบข้างต้น:

sed -i '/TEXT_TO_BE_REPLACED/c\This line is removed by the admin.' /tmp/foo

ทำงานได้ดีหากสตริง / บรรทัดทดแทนไม่ใช่ตัวแปร

ปัญหาก็คือว่าเมื่อวันที่ Redhat 5 \หลังจากที่หนีc $สอง\\อย่างไม่ทำงาน (อย่างน้อยใน Redhat 5)

จากการเข้าชมและทดลองใช้ฉันพบว่าข้อมูล\หลังcนั้นซ้ำซ้อนหากสตริง / บรรทัดทดแทนของคุณเป็นเพียงบรรทัดเดียว ดังนั้นฉันไม่ได้ใช้\หลังจากcนั้นใช้ตัวแปรเป็นบรรทัดทดแทนบรรทัดเดียวและมันก็เป็นความสุข

รหัสจะมีลักษณะดังนี้:

sed -i "/TEXT_TO_BE_REPLACED/c $REPLACEMENT_TEXT_STRING" /tmp/foo

หมายเหตุการใช้อัญประกาศแทนการอัญประกาศเดี่ยว


คุณยังสามารถใช้เครื่องหมายคำพูดเดี่ยวเช่นนี้: sed -i '/ TEXT_TO_BE_REPLACED / c' "$ VARIABLE" '' / tmp / foo
Alistair McIntyre

4

คำตอบทั้งหมดที่มีให้สันนิษฐานว่าคุณรู้บางอย่างเกี่ยวกับข้อความที่จะถูกแทนที่ซึ่งเหมาะสมเนื่องจากเป็นสิ่งที่ OP ถาม ฉันกำลังให้คำตอบที่ถือว่าคุณไม่รู้อะไรเกี่ยวกับข้อความที่จะถูกแทนที่และอาจมีบรรทัดแยกต่างหากในไฟล์ที่มีเนื้อหาเดียวกันหรือคล้ายกันที่คุณไม่ต้องการแทนที่ นอกจากนี้ฉันสมมติว่าคุณรู้หมายเลขบรรทัดของบรรทัดที่จะถูกแทนที่

ตัวอย่างต่อไปนี้แสดงให้เห็นถึงการลบหรือการเปลี่ยนแปลงข้อความตามหมายเลขบรรทัดเฉพาะ:

# replace line 17 with some replacement text and make changes in file (-i switch)
# the "-i" switch indicates that we want to change the file. Leave it out if you'd
#   just like to see the potential changes output to the terminal window.
# "17s" indicates that we're searching line 17
# ".*" indicates that we want to change the text of the entire line
# "REPLACEMENT-TEXT" is the new text to put on that line
# "PATH-TO-FILE" tells us what file to operate on
sed -i '17s/.*/REPLACEMENT-TEXT/' PATH-TO-FILE

# replace specific text on line 3
sed -i '3s/TEXT-TO-REPLACE/REPLACEMENT-TEXT/'

3

สำหรับจัดการไฟล์ปรับแต่ง

ฉันมากับวิธีแก้ปัญหานี้แรงบันดาลใจจากคำตอบ skensell

configLine [searchPattern] [replaceLine] [filePath]

มันจะ:

  • สร้างไฟล์หากไม่มีอยู่
  • แทนที่ทั้งบรรทัด (ทุกบรรทัด) ที่ตรงกับsearchPattern
  • เพิ่มreplaceLineที่ท้ายไฟล์หากไม่พบรูปแบบ

ฟังก์ชั่น:

function configLine {
  local OLD_LINE_PATTERN=$1; shift
  local NEW_LINE=$1; shift
  local FILE=$1
  local NEW=$(echo "${NEW_LINE}" | sed 's/\//\\\//g')
  touch "${FILE}"
  sed -i '/'"${OLD_LINE_PATTERN}"'/{s/.*/'"${NEW}"'/;h};${x;/./{x;q100};x}' "${FILE}"
  if [[ $? -ne 100 ]] && [[ ${NEW_LINE} != '' ]]
  then
    echo "${NEW_LINE}" >> "${FILE}"
  fi
}

เวทย์มนตร์สถานะการออกบ้ามาจากhttps://stackoverflow.com/a/12145797/1262663


2
bash-4.1$ new_db_host="DB_HOSTNAME=good replaced with 122.334.567.90"
bash-4.1$ 
bash-4.1$ sed -i "/DB_HOST/c $new_db_host" test4sed
vim test4sed
'
'
'
DB_HOSTNAME=good replaced with 122.334.567.90
'

มันใช้งานได้ดี


1

ใน makefile ของฉันฉันใช้สิ่งนี้:

@sed -i '/.*Revision:.*/c\'"`svn info -R main.cpp | awk '/^Rev/'`"'' README.md

PS: อย่าลืมว่า -i เปลี่ยนข้อความในไฟล์จริง ... ดังนั้นหากรูปแบบที่คุณกำหนดเป็น "Revision" จะเปลี่ยนไปคุณจะเปลี่ยนรูปแบบที่จะแทนที่ด้วย

ตัวอย่างผลลัพธ์:

Abc-Project เขียนโดย John Doe

รุ่น: 1190

ดังนั้นหากคุณตั้งค่ารูปแบบ "Revision: 1190" จะเห็นได้ชัดว่าไม่เหมือนกับที่คุณกำหนดให้เป็น "Revision:" เท่านั้น ...


1
cat find_replace | while read pattern replacement ; do
sed -i "/${pattern}/c ${replacement}" file    
done 

ไฟล์ find_replace มี 2 คอลัมน์, c1 ที่มีรูปแบบที่จะจับคู่, c2 ที่มีการแทนที่, วนวนเซดแทนที่แต่ละบรรทัดที่เชื่อมโยงหนึ่งในรูปแบบของตัวแปร 1


ไม่ผิดนี่เป็นความผิดหลายครั้ง รันsedหนึ่งครั้งด้วยไฟล์สคริปต์ที่มีการแทนที่ทั้งหมดที่คุณต้องการดำเนินการ การเรียกใช้sed -iไฟล์เดียวกันซ้ำ ๆ เป็นสิ่งที่น่ากลัวอย่างยิ่ง
tripleee

0

มันคล้ายกับข้างบนหนึ่ง ..

sed 's/[A-Za-z0-9]*TEXT_TO_BE_REPLACED.[A-Za-z0-9]*/This line is removed by the admin./'

3
ว่าการเปลี่ยนแปลงFOO=TEXT_TO_BE_REPLACEDไปFOO=This line ...จึงไม่เป็นไปตามข้อกำหนด
เจนส์

ใช่ .. ความต้องการของเราคือการแทนที่ทั้งบรรทัดด้วย 'บรรทัดนี้จะถูกลบโดยผู้ดูแลระบบ' หากเราพบกุญแจสำคัญ 'TEXT_TO_BE_REPLACED' คำสั่งดังกล่าวเป็นที่น่าพอใจ แก้ไขฉันถ้าความเข้าใจของฉันผิด .. @Jens
Annapureddy Hari

@AnnapureddyHari คำตอบนี้ใช้ไม่ได้หากข้อความก่อนหรือหลังสตริงการค้นหามีอะไรในนั้นนอกเหนือจาก A-Za-z0-9 มันล้มเหลวหากมีเครื่องหมายเท่ากับ Jens ชี้ให้เห็น ส่วน "FOO =" จะยังคงอยู่ คุณยังไม่ได้แทนที่ทั้งบรรทัด รหัสนี้เป็นสายตาสั้น ๆ เกี่ยวกับสิ่งที่อาจอยู่ในไฟล์ หากคุณหมายถึงไวด์การ์ดคุณควรใส่ไวลด์การ์ดดังที่คำตอบของ ธ ​​อร์แสดง
msouth

0

คำสั่งด้านล่างใช้งานได้สำหรับฉัน ซึ่งทำงานกับตัวแปร

sed -i "/\<$E\>/c $D" "$B"

แต่ข้อกำหนดใหม่ของฉันคือ SKIP แสดงความคิดเห็น (ขึ้นต้นด้วย #) บรรทัดขณะแทนที่ ในขณะที่เรากำลังแทนที่สายสมบูรณ์นี้จะแทนที่สายแสดงความคิดเห็นเช่นกันและคุณจะจบลงด้วยคุณสมบัติที่ซ้ำกัน หากใครมีทางออกสำหรับเรื่องนี้โปรดแจ้งให้เราทราบ
Ritesh Borkar

-1

ฉันมักจะใช้ regex เพื่อดึงข้อมูลจากไฟล์ฉันเพิ่งใช้มันเพื่อแทนที่คำพูดที่แท้จริง\"ด้วย//อะไร :-)

cat file.csv | egrep '^\"([0-9]{1,3}\.[0-9]{1,3}\.)' | sed  s/\"//g  | cut -d, -f1 > list.txt
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.