텍스트 파일을 처리하려고 하는데 특정 문자열 리터럴이 줄 끝에 나타나면 이를 생략합니다. 예를 들어:
원천:
ABC 123
DEF, characters I don't want
GHI, these characters are ok
원하는 출력:
ABC 123
DEF
GHI, these characters are ok
이렇게 하면 grep -v ', characters I don't want$'
전체 줄이 무시됩니다.
하위 문자열을 awk
원하기 때문에 간단한 열을 만들 수 없습니다., these characters are ok
cut
구분 기호는 여러 문자( )여야 하므로 구분 기호를 사용하여 분할 할 수 없습니다 , characters I don't want
.
Python을 사용하면 매우 간단합니다. 예를 들면 다음과 같습니다.string.split(", characters I don't want", 1)[0]
(여담으로, 이와 같은 복잡한 상황에서 Python이 더 읽기 쉽고 유지 관리가 용이할 때 grep, awk 또는 sed를 사용하는 사용 사례가 실제로 Python보다 더 나은지 궁금합니다.)
답변1
여기서 가장 분명한 것은 다음을 사용하는 것입니다 sed
.
<source sed "s/, characters I don't want\$//"
셸에서 이스케이프된 줄 끝에서 문자열을 찾으면 s
해당 문자열을 바꿉니다 (나중에 셸에 무언가가 나타날 경우를 대비해 미래의 증거로).$
\$
$/
해당 문자열 뒤의 항목(있는 경우)을 제거하려면 로 바꾸십시오. \$
단 , 사용자 로케일에서 유효한 텍스트가 아니더라도 끝까지 모든 항목이 일치하도록 .*
C의 로케일을 변경해야 합니다 ..*
<source LC_ALL=C sed "s/, characters I don't want.*//"
GNU grep
또는 호환 버전의 경우 Perl과 유사한 정규식 지원으로 빌드되면 다음과 같을 수 있습니다.
<source LC_ALL=C grep -Po "^.*?(?=(, characters I don't want)?\$)"
또는 해당 문자열 뒤의 모든 내용을 제거합니다(있는 경우).
<source LC_ALL=C grep -Po "^.*?(?=, characters I don't want|\$)"
또는 pcregrep
(Perl과 유사한 정규식 지원이 GNU에서 활성화된 경우 grep
이는 실제로 샘플 애플리케이션으로 제공되지만 pcregrep
GNU 이상의 기능을 갖춘 libpcre를 통해 수행됩니다 grep
):
<source pcregrep -o1 "^(.*?)(, characters I don't want)?\$"
또는 해당 문자열 뒤의 모든 내용을 제거합니다(있는 경우).
<source pcregrep -o1 "^(.*?)(, characters I don't want|\$)"
제거하려는 텍스트에 /
정규 표현식 연산자(의미 없는 개행이나 명령 인수나 환경 변수에 전달할 수 있는 NUL 문자 제외)를 포함할 수 있고 쉘 변수에 저장된 경우 다음과 같이 할 수 있습니다.아니요이를 사용하면 명령 주입 취약점이 생길 수 있습니다.sed "s/$string\$//"
Perl-grep의 경우 다음을 사용할 수 있습니다.
string='/.*\^$'
<source LC_ALL=C grep -Po "^.*?(?=(\Q$string)?\$)"
<source pcregrep -o1 "^(.*?)(\Q$string\E)?\$"
또는 해당 문자열 뒤의 모든 내용을 제거합니다(있는 경우).
<source LC_ALL=C grep -Po "^.*?(?=\Q$string|\$)"
<source pcregrep -o1 "^(.*?)(\Q$string\E|\$)"
이는 비록 심각한 결과를 가져오지는 않더라도 여전히 $string
격리된 s에 대한 질식을 야기합니다 .\E
sed
또는 임의의 문자열을 전달하기 위한 메커니즘을 사용하여 옵션이 있는 모드 perl
에서 직접 사용할 수 있습니다 (여기서는 대략적인 옵션 전달에 사용되지만 직접 사용할 수도 있습니다 (파이썬에 해당 ). 또는 환경 변수( 연관 배열에 매핑됨)). 문자열 은 정규 표현식에서 인용될 수 있습니다( 여기서는 in이 문제가 되지 않습니다):sed
-p
-s
@ARGV
sys.argv
%ENV
\Q
\E
$string
<source perl -spe 's/\Q$string\E$//' -- -string="$string"
또는 해당 문자열 뒤의 모든 내용을 제거합니다(있는 경우).
<source perl -spe 's/\Q$string\E.*$//' -- -string="$string"
perl
기본적으로 입력은 사용자의 로캘 문자 집합으로 인코딩되지 않고 바이트로 처리되므로 여기서 로캘을 변경할 필요가 없습니다.
대조적으로, 줄 구분 기호는 패턴 공간( sed
기본적 $_
으로 작동하는 곳 perl
)에 포함되며 해당 정규식 연산자는 주제 끝이나 주제 끝의 줄 구분 기호 앞에 일치하므로 처리할 수 있습니다. 구분된 줄과 무제한된 줄.s///
$
답변2
awk를 사용하십시오.
$ awk 'n=index($0 RS,", characters I don\047t want" RS){$0=substr($0,1,n-1)} 1' file
ABC 123
DEF
GHI, these characters are ok
이는 리터럴 문자열 비교를 수행하므로 정규 표현식 메타 문자가 포함된 문자열을 다음 입력과 일치시키려고 시도하는 경우에도 작동합니다.
$ cat file2
ABC 123
DEF, .*, .*
GHI, .* ok
예상되는 결과는 다음과 같습니다.
$ awk 'n=index($0 RS,", .*" RS){$0=substr($0,1,n-1)} 1' file2
ABC 123
DEF, .*
GHI, .* ok
정규식 메타 문자에 관심이 없다면 다음을 수행할 수 있습니다.
$ awk '{sub(/, characters I don\047t want$/,"")} 1' file
ABC 123
DEF
GHI, these characters are ok
그러나 예상치 못한 결과가 나타납니다.
$ awk '{sub(/, .*$/,"")} 1' file2
ABC 123
DEF
GHI
그리고 예상되는 출력을 얻으려면 메타 문자를 리터럴로 만들기 위해 이스케이프해야 합니다.
$ awk '{sub(/, \.\*$/,"")} 1' file2
ABC 123
DEF, .*
GHI, .* ok
실제로 원하는 것은 문자 그대로의 문자열 비교뿐이라는 점을 고려하면 이는 다루기 어려워집니다.
바라보다http://awk.freeshell.org/PrintASingleQuote\047
대신에 왜 '
.
python 대신 awk가 사용되는 이유 - awk는 필수 POSIX 도구이므로 모든 POSIX 호환 Unix 설치에 존재하도록 보장되는 반면, python은 그렇지 않으며 awk로 텍스트를 조작하는 데 일반적으로 awk Python을 사용하는 것보다 훨씬 적은 코드가 필요합니다. . 나는 우리가 어느 쪽이 읽고 유지하기 더 쉬운지에 대해 동의해야 한다고 생각합니다.
답변3
줄 끝의 내용을 미리 알고 있으면 변수 확장과 같은 기능을 지원하는 Bash 및 셸에서 해당 내용을 필터링하는 것이 상당히 쉽습니다. 예를 들어:
#!/usr/bin/env bash
line='DEF, characters I do not want'
echo "${line%, characters I do not want}"
다음을 인쇄합니다:
DEF
이 구문은 끝에서 내용을 제거한 후 문자열의 내용을 반환합니다 ${var%string}
. 이 예에서 삭제할 문자열은 " "입니다. 문자열이 끝에 있지 않으면 전체 콘텐츠가 반환됩니다. 변수의 시작 부분에서 문자열을 제거하는 변형과 내용 중간에 있는 문자열을 대체하거나 제거하는 대체 변형이 있습니다.$var
%
, characters I do not want
$line
위의 예에서는 변수에 문자열을 할당할 때 작은따옴표를 사용하여 발생하는 복잡함을 피하기 위해 don't
->가 변경되었음을 인정합니다 .do not
$line
이 접근 방식의 장점은 스크립트가 간단한 필터링을 수행하기 위해 외부 명령을 호출할 필요가 없다는 것입니다. 하지만 이것이 Python의 강력한 기능을 대체할 수 있을까요?. 아마도 아닐 수도 있지만, 이 작업에 Python 대신 쉘 스크립트를 사용하도록 동기를 부여하는 다른 요인이 있을 수 있습니다.