Bash 명령에서 텍스트 파일 내부 찾기 및 바꾸기


561

찾은 내용을 주어진 입력 문자열을 대체 말할 수있는 가장 간단한 방법은 무엇인가 abc말을하고, 다른 문자열로 대체 할 XYZ파일은 /tmp/file.txt?

앱을 작성하고 IronPython을 사용하여 SSH를 통해 명령을 실행하고 있습니다. 그러나 유닉스를 잘 모르고 무엇을 찾아야할지 모르겠습니다.

Bash는 명령 줄 인터페이스가 아니라 매우 강력한 스크립팅 언어가 될 수 있다고 들었습니다. 따라서 이것이 사실이라면 나는 당신이 이와 같은 행동을 수행 할 수 있다고 가정합니다.

bash로 할 수 있습니까? 목표를 달성하는 가장 간단한 (한 줄) 스크립트는 무엇입니까?

답변:


928

가장 쉬운 방법은 sed (또는 perl)를 사용하는 것입니다.

sed -i -e 's/abc/XYZ/g' /tmp/file.txt

-i옵션 으로 인해 내부 편집을 수행하기 위해 sed를 호출합니다 . 이것은 bash에서 호출 할 수 있습니다.

정말로 bash 만 사용하고 싶다면 다음과 같이 할 수 있습니다.

while read a; do
    echo ${a//abc/XYZ}
done < /tmp/file.txt > /tmp/file.txt.t
mv /tmp/file.txt{.t,}

이것은 각 행을 반복하여 대체를 수행하고 임시 파일에 기록합니다 (입력을 방해하지 않으려 고 함). 마지막 이동은 임시로 원래 이름으로 이동합니다.


3
mv를 호출하는 것은 sed를 사용하는 것만 큼 '비 Bash'입니다. 나는 거의 같은 메아리를 말했지만 껍질이 내장되어 있습니다.
slim

5
sed에 대한 -i 인수는 Solaris에는 존재하지 않지만 다른 구현은 생각할 것이므로 명심하십시오. 그냥 알아내는 데 몇 분을 보냈습니다 ...
Panky

2
자기에 대한 참고 : 일반의 표현에 대한 sed: s/..../..../ - Substitute/g - Global
검사

89
invalid command code C오류가 발생한 Mac 사용자를위한 참고 사항 ... 전체 대체의 경우 BSD 는 지정된 확장자를 가진 백업 파일을 저장하므로 플래그 sed뒤에 파일 확장자가 필요합니다 -i. 예를 들어 다음 sed -i '.bak' 's/find/replace/' /file.txt 과 같이 빈 문자열을 사용하여 백업을 건너 뛸 수 있습니다.sed -i '' 's/find/replace/' /file.txt
Austin

8
팁 : 대소 문자를 구분하지 않는 repalce 사용을 원할 경우s/abc/XYZ/gi
Boris D.

166

파일 조작은 일반적으로 Bash가 아니라 Bash가 호출 한 프로그램에 의해 수행됩니다. 예 :

perl -pi -e 's/abc/XYZ/g' /tmp/file.txt

-i플래그는 내부 교체를 지시합니다.

man perlrun원본 파일을 백업하는 방법을 포함하여 자세한 내용을 참조하십시오 .


37
내 순수 주의자는 시스템에서 Perl을 사용할 수 있다고 확신 할 수 없다고 말합니다. 그러나 요즘은 그런 경우가 거의 없습니다. 아마도 나는 내 나이를 보여주고있다.
slim

3
더 복잡한 예를 보여줄 수 있습니까? "chdir / blah"를 "chdir / blah2"로 바꾸는 것과 같은 것. 나는 시도 perl -pi -e 's/chdir (?:\\/[\\w\\.\\-]+)+/chdir blah/g' text했지만 패턴과 다음 단어 사이에 공백이 없다는 것은 -e 줄 1에서 더 이상 사용되지 않는다는 오류가 계속 발생합니다. ? : \\ / -e 라인 1에서.
CMCDragonkai

이 답변을 확인 @CMCDragonkai : stackoverflow.com/a/12061491/2730528
알폰소 산티아고

69

이걸 우연히 발견했을 때 놀랐습니다 ...

패키지 replace와 함께 제공 되는 명령이 "mysql-server"있으므로 설치 한 경우 시도해보십시오.

# replace string abc to XYZ in files
replace "abc" "XYZ" -- file.txt file2.txt file3.txt

# or pipe an echo to replace
echo "abcdef" |replace "abc" "XYZ"

이에 man replace대한 자세한 내용 을 참조하십시오 .


12
두 가지가 가능합니다 : a) replace유용한 독립적 인 도구이며 MySQL 사람들은 별도로 릴리스하고 그것에 의존해야합니다. b) replace약간의 MySQL o_O가 필요합니다. :)
Philip Whitehouse 14'14 /

Mac에서만 작동합니까? 내 우분투에서 그 명령은하지 않습니다 CentOS는 존재

1
mysql-server패키지가 설치되어 있지 않기 때문 입니다. @rayro replace가 지적한 것처럼 그 일부입니다.
Phius

2
"경고 : replace는 더 이상 사용되지 않으며 향후 버전에서 제거 될 것입니다."
Steven Vachon

1
Windows에서 REPLACE 명령을 실행하지 않도록주의하십시오! Windows에서 REPLACE 명령은 파일의 빠른 복제를위한 것입니다. 이 토론과 관련이 없습니다.
Maor

52

이것은 오래된 게시물이지만 @ centurian과 같이 변수를 사용하려는 사람은 작은 따옴표가 아무것도 확장되지 않는다는 것을 의미한다고 말했습니다.

변수를 가져 오는 간단한 방법은 문자열 연결을 수행하는 것입니다. 이는 bash에서 병렬로 수행되므로 다음과 같이 작동합니다.

sed -i -e "s/$var1/$var2/g" /tmp/file.txt

39

다른 쉘과 마찬가지로 Bash는 다른 명령을 조정하는 도구 일뿐입니다. 일반적으로 표준 UNIX 명령을 사용하려고 시도하지만 Bash를 사용하여 컴파일 된 프로그램, 다른 쉘 스크립트, Python 및 Perl 스크립트 등을 포함하여 무엇이든 호출 할 수 있습니다.

이 경우 몇 가지 방법이 있습니다.

파일을 읽고 다른 파일에 쓰려면 검색 / 바꾸기를 수행하면서 sed를 사용하십시오.

sed 's/abc/XYZ/g' <infile >outfile

편집기에서 파일을 열고 편집 한 후 저장하는 것처럼 파일을 제자리에서 편집하려면 라인 편집기 'ex'에 지시 사항을 제공하십시오.

echo "%s/abc/XYZ/g
w
q
" | ex file

Ex는 전체 화면 모드가없는 vi와 같습니다. vi의 ':'프롬프트에서와 동일한 명령을 제공 할 수 있습니다.


33

나는이 스레드를 다른 사람들과 함께 발견했으며 가장 완벽한 답변을 포함하고 있음을 동의하므로 내 것을 추가하고 있습니다.

  1. sed그리고 ed손으로 너무 유용합니다. @Johnny 에서이 코드를보십시오 :

    sed -i -e 's/abc/XYZ/g' /tmp/file.txt
  2. 내 제한이 쉘 스크립트에서 사용되는 경우, "abc"또는 "XYZ"대신 변수를 사용할 수 없습니다. BashFAQ은 내가 적어도 이해하는 것을 동의 것으로 보인다. 그래서 나는 사용할 수 없습니다 :

    x='abc'
    y='XYZ'
    sed -i -e 's/$x/$y/g' /tmp/file.txt
    #or,
    sed -i -e "s/$x/$y/g" /tmp/file.txt

    그러나 우리는 무엇을 할 수 있습니까? @Johnny는 사용 while read...하지만 불행히도 그 이야기의 끝은 아닙니다. 다음은 나와 잘 작동했습니다.

    #edit user's virtual domain
    result=
    #if nullglob is set then, unset it temporarily
    is_nullglob=$( shopt -s | egrep -i '*nullglob' )
    if [[ is_nullglob ]]; then
       shopt -u nullglob
    fi
    while IFS= read -r line; do
       line="${line//'<servername>'/$server}"
       line="${line//'<serveralias>'/$alias}"
       line="${line//'<user>'/$user}"
       line="${line//'<group>'/$group}"
       result="$result""$line"'\n'
    done < $tmp
    echo -e $result > $tmp
    #if nullglob was set then, re-enable it
    if [[ is_nullglob ]]; then
       shopt -s nullglob
    fi
    #move user's virtual domain to Apache 2 domain directory
    ......
  3. 다음과 같이 nullglob설정되어 있는지 확인할 수 있듯이 *as를 포함하는 문자열이 있으면 이상하게 동작합니다 .

    <VirtualHost *:80>
     ServerName www.example.com

    이것은

    <VirtualHost ServerName www.example.com

    끝 꺾쇠 괄호가 없으며 Apache2도로드 할 수 없습니다.

  4. 이러한 종류의 구문 분석은 한 번의 검색 및 바꾸기보다 속도가 느려 야하지만 이미 살펴본 것처럼 한 번의 구문 분석주기에서 작동하는 4 가지 다른 검색 패턴에 대한 4 개의 변수가 있습니다.

주어진 문제에 대한 가정으로 생각할 수있는 가장 적합한 솔루션입니다.


12
당신의 (2)에서-당신은 할 수 sed -e "s/$x/$y/"있고 작동합니다. 큰 따옴표가 아닙니다. 변수 자체의 문자열에 특별한 의미의 문자가 포함되어 있으면 심각하게 혼동 될 수 있습니다. 예를 들어 x = "/"또는 x = "\"인 경우입니다. 이러한 문제가 발생하면이 작업에 쉘 사용을 중단해야한다는 의미 일 수 있습니다.
slim

안녕하세요, 당신도 펄 사용에 반대하는 것을 알았습니다. 당신의 해결책은 무엇입니까? 실제로 파일의 경로를 동적으로 변경하고 싶기 때문에 문자열에 많은 /가 있음을 의미합니다!
Mahdi

20

당신은 사용할 수 있습니다 sed:

sed -i 's/abc/XYZ/gi' /tmp/file.txt

사용 -i이 발견하지 않도록 텍스트 경우 "경우 무시"에 대한은 abcABC이나 AbC

당신은 사용 find하고 sed당신이 당신의 이름을 모르는 경우 :

find ./ -type f -exec sed -i 's/abc/XYZ/gi' {} \;

모든 파이썬 파일에서 찾기 및 바꾸기 :

find ./ -iname "*.py" -type f -exec sed -i 's/abc/XYZ/gi' {} \;

12

ed명령을 사용하여 파일 내 검색 및 바꾸기를 수행 할 수도 있습니다 .

# delete all lines matching foobar 
ed -s test.txt <<< $'g/foobar/d\nw' 

" 를 사용하여 스크립트를 통해 파일 편집하기ed "를 참조하십시오 .


3
이 솔루션은 (와 달리 sed -i <pattern> <filename>) GNU / FreeBSD (Mac OSX) 비 호환성과는 독립적입니다 . 아주 좋아요!
Peterino

11

작업중 인 파일이 너무 크지 않고 일시적으로 변수에 저장하는 것이 문제가되지 않으면 전체 파일에 Bash 문자열 대체를 한 번에 사용할 수 있습니다. 한 줄씩 넘길 필요가 없습니다.

file_contents=$(</tmp/file.txt)
echo "${file_contents//abc/XYZ}" > /tmp/file.txt

전체 파일 내용은 줄 바꿈을 포함하여 하나의 긴 문자열로 처리됩니다.

XYZ는 예를 들어 변수 일 수 있으며, $replacement여기에서 sed를 사용하지 않을 경우 얻을 수있는 이점 중 하나는 검색 또는 바꾸기 문자열에 sed 패턴 구분 문자 (일반적으로 /는 아니지만)가 포함될 수 있다는 점에 대해 걱정할 필요가 없다는 것입니다. 단점은 정규식이나 sed의보다 정교한 조작을 사용할 수 없다는 것입니다.


탭 문자와 함께 사용하기위한 팁이 있습니까? 어떤 이유로 내 스크립트는 sed가 많은 sed 에서이 방법으로 변경 한 후 탭이없는 것을 찾지 못했습니다.
Brian Hannay

2
바꾸려는 문자열에 탭을 넣으려면 Bash의 "달러 단위 작은 따옴표"구문을 사용하여 탭을 $ '\ t'로 표시하고 $ echo 'tab'$을 수행하면됩니다. '\ t' '분리됨> 테스트 파일; $ file_contents = $ (<테스트 파일); $ echo "$ {file_contents // $ '\ t'/ TAB}"; tabTABseparated`
johnraff


5

다음 쉘 명령을 시도하십시오.

find ./  -type f -name "file*.txt" | xargs sed -i -e 's/abc/xyz/g'

4
이것은 "우연히 모든 서브 디렉토리의 모든 파일을 어떻게 수행합니까?"에 대한 훌륭한 답변이지만 여기에서 요구되는 것은 아닙니다.
tripleee

이 구문은없는 작업의 BSD 버전에 대한 것 sed, 사용하는 sed -i''대신.
kenorb

5

파일에서 비 대화식으로 텍스트를 편집하려면 vim과 같은 내부 텍스트 편집기가 필요합니다.

다음은 명령 행에서 사용하는 간단한 예입니다.

vim -esnc '%s/foo/bar/g|:wq' file.txt

이것은 기본적으로 동일한 ex 편집기 의 @slim 답변 과 동일합니다.

다음은 ex실용적인 예입니다.

파일에서 텍스트 foo를 바꾸 bar려면 :

ex -s +%s/foo/bar/ge -cwq file.txt

여러 파일의 후행 공백 제거 :

ex +'bufdo!%s/\s\+$//e' -cxa *.txt

문제 해결 (터미널이 멈췄을 때) :

  • -V1상세 메시지를 표시하려면 param을 추가하십시오 .
  • 다음에 의해 강제 종료하십시오 : -cwq!.

또한보십시오:


대화식으로 교체를 원했습니다. 따라서 "vim -esnc '% s / foo / bar / gc | : wq'file.txt"를 시도했습니다. 그러나 이제 터미널이 막혔습니다. bash 쉘이 이상하게 동작하지 않고 어떻게 대화식으로 교체 할 수 있을까요?
vineeshvs 2009

-V1강제 종료 하려면 디버그하고 추가 하고을 사용하십시오 wq!.
kenorb

2

bash 스크립트 내에서도 파이썬을 사용할 수 있습니다. 나는 여기에있는 최고의 답변 중 많은 성공을 거두지 못했고 루프가 필요없이 작동한다는 것을 알았습니다.

#!/bin/bash
python
filetosearch = '/home/ubuntu/ip_table.txt'
texttoreplace = 'tcp443'
texttoinsert = 'udp1194'

s = open(filetosearch).read()
s = s.replace(texttoreplace, texttoinsert)
f = open(filetosearch, 'w')
f.write(s)
f.close()
quit()

1

rpl 명령을 사용할 수 있습니다. 예를 들어 전체 PHP 프로젝트에서 도메인 이름을 변경하려고합니다.

rpl -ivRpd -x'.php' 'old.domain.name' 'new.domain.name' ./path_to_your_project_folder/  

이것은 명백한 원인이 아니지만 매우 빠르고 유용합니다. :)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.