백슬래시로 전달된 구분 기호를 무시하는 방법은 무엇입니까?

백슬래시로 전달된 구분 기호를 무시하는 방법은 무엇입니까?

다음과 같은 사용 사례가 있습니다.

echo "some comment char '\;' embedded in strings   ; along with inline comments" \
| cut -d';' -f 1

제 생각에는:

some comment char ';' embedded in strings

나는 얻다:

some comment char '

이 사용 사례에 표시된 대로 잘라내도록 구성된 구분 기호를 숨기려면 어떻게 해야 합니까? 이상적으로 cut은 백슬래시를 읽고 존중하지만, 그렇지 않은 경우 다른 방법이 있습니까?

답변1

모든 Unix 시스템의 모든 쉘에서 awk를 사용하십시오.

$ echo "some comment char '\;' embedded in strings   ; along with inline comments" |
awk -F';' '{gsub(/\\\\/,RS); gsub(/\\;/,"\\\\"); gsub(/\\\\/,";",$1); gsub(RS,"\\",$1); print $1}'
some comment char ';' embedded in strings

그리고 빌려@Stéphane의 입력 파일 예시:

$ cat file
foo\;bar;baz
foo\\;bar;baz

$ awk -F';' '{gsub(/\\\\/,RS); gsub(/\\;/,"\\\\"); gsub(/\\\\/,";",$1); gsub(RS,"\\",$1); print $1}' file
foo;bar
foo\

더 많은 필드가 있는 행으로 확장합니다.

$ cat file
foo\;bar;baz
foo\\;bar;baz
foo\\;bar\;this\;that\\;baz;here\;and\;there

필요에 따라 일부 또는 모든 필드를 인쇄할 수 있습니다. 여기서는 원래 줄을 먼저 출력하고 단일 필드를 포함하는 각 출력 줄의 시작 부분에 필드 번호를 출력합니다.

$ awk -F';' '{print; gsub(/\\\\/,RS) gsub(/\\;/,"\\\\"); for (i=1; i<=NF; i++) { gsub(/\\\\/,";",$i); gsub(RS,"\\",$i); print "   " i, $i }; print "---" }' file
foo\;bar;baz
   1 foo;bar
   2 baz
---
foo\\;bar;baz
   1 foo\
   2 bar
   3 baz
---
foo\\;bar\;this\;that\\;baz;here\;and\;there
   1 foo\
   2 bar;this;that\
   3 baz
   4 here;and;there

위에:

  1. \\현재 입력 라인( )의 각 문자를 $0개행 문자( 의 기본값 RS)로 변환합니다. 이는 개행 문자로 구분된 레코드에 존재할 수 없는 문자열이므로 \\;이스케이프된 절반 대신 입력 백슬래시에서 이스케이프된 것으로 처리 할 수 있습니다. -문자 콜론, 그 다음
  2. 각각을 로 변환 \;합니다 . 이는 이제 $0에 존재할 수 없는 문자열이기도 합니다. 왜냐하면 우리는 이를 제거하기 위해 모두 s 로 변환하기 때문입니다.$0\\RS;
  3. 수정 작업으로 $0인해 awk는 $0나머지 각 field에 대한 필드로 다시 분할되어 ;원하는 대상 문자열을 넣은 $1다음
  4. \\위의 2단계에서 생성된 모든 것을 then $1으로 변환합니다 .;
  5. RS위의 1단계에서 생성된 모든 항목을 $1다시 변환한 \\다음
  6. 우리는 필드를 인쇄합니다.$1

이 방법은 RSPOSIX에서 정의한 모든 리터럴 문자열에 대해 작동하며, RSGNU awk와 같은 일부 awk에서 지원하는 정규 표현식인 경우 정규 표현식과 일치하는 정규 표현식 메타 문자가 없는 문자열을 대체용으로 제안합니다.RS

답변2

GNU grep또는 호환 기능을 사용하십시오(비표준이지만 현재는 매우 일반적인 -o옵션).

grep -Eo '^(\\.|[^\\;])*'

이는 0개 이상의 ( )1 시퀀스를 일치시키고 출력하며 o, 그 뒤에는 이스케이프뿐만 아니라 이스케이프도 포함하는 단일 문자( ) 또는 행의 시작 부분( ) 이외의 모든 문자가 옵니다.*\.;\\;^

예:

$ cat file
foo\;bar;baz
foo\\;bar;baz
$ grep -Eo '^(\\.|[^\\;])*' file
foo\;bar
foo\\

sed 's/\\\(.\)/\1/g'이스케이프를 제거하려면 해당 옵션도 지원하는 경우 전체 작업을 파이프하거나 수행하십시오.sedsed-E

$ sed -E 's/^((\\.|[^\\;])*).*/\1/; s/\\(.)/\1/g' file
foo;bar
foo\

또는 다음을 사용하여 perl:

$ perl -lpe 's/^(\\.|[^;])*+\K.*//; s/\\(.)/$1/g' file
foo;bar
foo\

1 그러나 grep -o빈 일치 항목은 출력되지 않습니다.

관련 정보