Thay thế toàn bộ dòng chứa chuỗi bằng Sed


319

Tôi có một tệp văn bản có một dòng cụ thể như

sometext sometext sometext TEXT_TO_BE_REPLACED sometext sometext sometext

Tôi cần thay thế toàn bộ dòng trên bằng

This line is removed by the admin.

Từ khóa tìm kiếm là TEXT_TO_BE_REPLACED

Tôi cần phải viết một kịch bản shell cho điều này. Làm thế nào tôi có thể đạt được điều này bằng cách sử dụng sed?


@Scharron Tôi đã thử sed -rne 's / (TEXT_TO_BE_REPLACED) \ s + \ w + / \ 1 yyy / xxx' Nhưng điều đó sẽ chỉ thay thế yyy bằng xxx trong chuỗi nếu có bất kỳ yyy nào. Trong trường hợp của tôi, văn bản không được sửa ... tất cả những gì tôi có là TEXT_TO_BE_REPLACED.
Raul

đó không phải là một biểu thức sed hợp lệ. Bạn có chắc chắn muốn nó với sed? Bất kỳ ngôn ngữ lập trình nào có biểu thức chính quy tốt đều có thể thay thế bạn (tìm kiếm chức năng phụ). Điều đó sẽ dễ hơn là tự mình hiểu về sed
Scharron

@Scharron Vâng, nó được thực hiện với shell script nên tôi đoán sed là lựa chọn tốt nhất của tôi.
Rulul

Câu trả lời:


483

Bạn có thể sử dụng lệnh thay đổi để thay thế toàn bộ dòng và -icờ để thực hiện thay đổi tại chỗ. Ví dụ: sử dụng GNU sed:

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

4
Lưu ý rằng bạn cần một khoảng trắng trước c \. Tôi vừa chỉnh sửa để thêm cái này.
Marcus Downing

27
@MarcusDowning GNU sed không yêu cầu không gian; nó hoạt động tốt như ban đầu được đăng. Nếu sed cụ thể của bạn yêu cầu không gian, thì bằng mọi cách, hãy lưu ý rằng sed nào không tương thích và thêm lời mời cần thiết như một nhận xét. Tuy nhiên, xin vui lòng không thay đổi mã làm việc trong một câu trả lời được chấp nhận.
Todd A. Jacobs

7
Làm cách nào tôi có thể sử dụng một biến thay vì văn bản "Đây ..."? Nếu tôi thay thế nó bằng $ biến, nó không in nội dung của nó mà là tên biến.
Steven

18
Có một vấn đề với c\ khi được theo dõi trực tiếp bởi một biến: …c\$VAR…Dấu gạch chéo ngược sẽ thoát khỏi đồng đô la. Trong trường hợp này, tôi (bash / sed trên Ubuntu 15.10) đã phải viết…c\\$VAR…
1

6
trên mac sử dụng : sed -i '' '/TEXT_TO_BE_REPLACED/c\This line is removed by the admin.' /tmp/foo; (khi thông số đầu tiên trống, nó chỉnh sửa trong tệp, nếu không sẽ tạo bản sao lưu)
AndreDurao

152

Bạn cần sử dụng wildards ( .*) trước và sau để thay thế toàn bộ dòng:

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

Cảm ơn bạn, có tôi làm việc: sed 's /.* <expression> * / <expression> SE_LABEL = ABC <expression> / g.' MYR2.xml> test.txt
Nasri Najib

9
Điều này đang hoạt động trên Mac OS X Yosemite với ngoại lệ là tôi đang sử dụng các cờ -i và -e như sau:sed -i -e "s/.*search_string.*/Replacement_line/' file_being_searched.txt
Kent Bull

1
@KentJohnson Tôi nghĩ rằng bạn có dấu ngoặc kép trong lệnh của bạn.
HashHazard

@MBarnett bạn nói đúng, tôi nên có hai dấu ngoặc kép ở đó.
Kent Bull

2
Chỉ cần cho các thông tin đầy đủ. Để đặt nó tại chỗ, người ta có thể thêm -itùy chọn
Temak

20

Câu trả lời được chấp nhận không hoạt động với tôi vì nhiều lý do:

  • phiên bản sed của tôi không thích -ivới phần mở rộng có độ dài bằng không
  • cú pháp của c\lệnh là lạ và tôi không thể làm cho nó hoạt động
  • Tôi đã không nhận ra một số vấn đề của tôi đến từ những nhát chém không được giải thoát

Vì vậy, đây là giải pháp tôi nghĩ ra mà tôi nghĩ nên làm việc cho hầu hết các trường hợp:

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/
}

Vì vậy, việc sử dụng mẫu để khắc phục vấn đề đặt ra:

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

18

Câu trả lời trên:

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

Hoạt động tốt nếu chuỗi / dòng thay thế không phải là một biến.

Vấn đề là trên Redhat 5 \sau khi cthoát $. Một đôi \\cũng không hoạt động (ít nhất là trên Redhat 5).

Thông qua hit và dùng thử, tôi phát hiện ra rằng \sau đó clà dư thừa nếu chuỗi / dòng thay thế của bạn chỉ là một dòng duy nhất. Vì vậy, tôi đã không sử dụng \sau c, sử dụng một biến như một dòng thay thế duy nhất và đó là niềm vui.

Mã này sẽ trông giống như:

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

Lưu ý việc sử dụng dấu ngoặc kép thay vì dấu ngoặc đơn.


bạn vẫn có thể sử dụng các trích dẫn đơn như thế này: sed -i '/ TEXT_TO_BE_REPLACED / c' "$ VARIABLE" '' / tmp / foo
Alistair McIntyre

4

Tất cả các câu trả lời được cung cấp cho đến nay đều cho rằng bạn biết điều gì đó về văn bản sẽ được thay thế, điều đó có ý nghĩa, vì đó là những gì OP yêu cầu. Tôi đang cung cấp một câu trả lời cho rằng bạn không biết gì về văn bản sẽ được thay thế và có thể có một dòng riêng trong tệp có cùng nội dung hoặc tương tự mà bạn không muốn thay thế. Hơn nữa, tôi giả sử bạn biết số dòng của dòng sẽ được thay thế.

Các ví dụ sau đây thể hiện việc xóa hoặc thay đổi văn bản theo số dòng cụ thể:

# 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

để thao tác với tập tin cấu hình

tôi đã đưa ra giải pháp này lấy cảm hứng từ câu trả lời của skensell

configLine [searchPattern] [replaceLine] [filePath]

nó sẽ:

  • tạo tập tin nếu không tồn tại
  • thay thế toàn bộ dòng (tất cả các dòng) trong đó searchPotype khớp
  • thêm thay thếLine vào cuối tập tin nếu không tìm thấy mẫu

Chức năng:

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
}

ma thuật trạng thái thoát điên đến từ 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
'

nó hoạt động tốt


1

Trong makefile của tôi, tôi sử dụng cái này:

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

Tái bút: KHÔNG quên rằng -i thực sự thay đổi văn bản trong tệp ... vì vậy nếu mẫu bạn xác định là "Sửa đổi" sẽ thay đổi, bạn cũng sẽ thay đổi mẫu để thay thế.

Ví dụ đầu ra:

Dự án Abc được viết bởi John Doe

Sửa đổi: 1190

Vì vậy, nếu bạn đặt mẫu "Sửa đổi: 1190" thì rõ ràng không giống như bạn đã định nghĩa chúng là "Sửa đổi:" chỉ ...


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

Tập tin find_Vplace chứa 2 cột, c1 có mẫu phù hợp, c2 có thay thế, vòng lặp sed thay thế mỗi dòng kết hợp một trong các mẫu của biến 1


Không, điều này là sai trên một số tính. Chạy sedmột lần với tệp tập lệnh chứa tất cả các thay thế bạn muốn thực hiện. Chạy sed -itrên cùng một tập tin nhiều lần là một antipotype khủng khiếp.
tripleee

0

Nó tương tự như trên ..

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

3
Điều đó thay đổi FOO=TEXT_TO_BE_REPLACEDđể FOO=This line ...không đáp ứng các đặc điểm kỹ thuật.
Jens

Có .. Yêu cầu của chúng tôi là thay thế toàn bộ dòng bằng 'Dòng này bị quản trị viên xóa.' nếu chúng tôi tìm thấy pattren khóa 'TEXT_TO_BE_REPLACED'. Lệnh trên là thỏa mãn. Sửa lỗi cho tôi nếu hiểu biết của tôi là sai .. @Jens
Annapureddy Hari

@AnnapureddyHari câu trả lời này không hoạt động nếu văn bản trước hoặc sau chuỗi tìm kiếm có bất cứ thứ gì trong đó ngoài A-Za-z0-9. Nó thất bại nếu có một dấu bằng, như Jens đã chỉ ra. Phần "FOO =" sẽ vẫn còn; bạn đã không thay thế toàn bộ dòng. Mã này là thiển cận về những gì có thể có trong tập tin. Nếu bạn có nghĩa là ký tự đại diện, bạn nên đặt ký tự đại diện, như câu trả lời của Thor cho thấy.
msouth

0

Lệnh dưới đây đang làm việc cho tôi. Mà đang làm việc với các biến

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

Nhưng yêu cầu mới của tôi là SKIP nhận xét (bắt đầu bằng dòng #) trong khi thay thế. Vì chúng tôi đang thay thế dòng hoàn chỉnh, điều này cũng sẽ thay thế các dòng nhận xét và bạn sẽ kết thúc với các thuộc tính trùng lặp. Nếu ai có giải pháp cho việc này xin vui lòng cho tôi biết.
Ritesh Borkar

-1

Tôi rất thường sử dụng regex để trích xuất dữ liệu từ các tệp mà tôi vừa sử dụng để thay thế trích dẫn \"bằng chữ //không có gì :-)

cat file.csv | egrep '^\"([0-9]{1,3}\.[0-9]{1,3}\.)' | sed  s/\"//g  | cut -d, -f1 > list.txt
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.