sed - 파일에서 마지막으로 나타나는 문자열(쉼표)을 제거하시겠습니까?

sed - 파일에서 마지막으로 나타나는 문자열(쉼표)을 제거하시겠습니까?

매우 큰 CSV 파일이 있습니다. ,sed (또는 이와 유사한 것)를 사용하여 마지막 항목을 어떻게 제거합니까 ?

...
[11911,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11912,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11913,0,"BUILDER","2014-10-15","BUILDER",0,0],
]

원하는 출력

...
[11911,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11912,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11913,0,"BUILDER","2014-10-15","BUILDER",0,0]
]

다음 sed 명령은 줄당 마지막 항목을 삭제하지만 파일당 삭제를 원합니다.

sed -e 's/,$//' foo.csv

이것도 작동하지 않습니다

sed '$s/,//' foo.csv

답변1

사용awk

쉼표가 항상 두 번째부터 마지막 ​​줄 끝에 있는 경우:

$ awk 'NR>2{print a;} {a=b; b=$0} END{sub(/,$/, "", a); print a;print b;}'  input
[11911,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11912,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11913,0,"BUILDER","2014-10-15","BUILDER",0,0]
]

사용 awkbash

$ awk -v "line=$(($(wc -l <input)-1))" 'NR==line{sub(/,$/, "")} 1'  input
[11911,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11912,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11913,0,"BUILDER","2014-10-15","BUILDER",0,0]
]

사용sed

$ sed 'x;${s/,$//;p;x;};1d'  input
[11911,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11912,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11913,0,"BUILDER","2014-10-15","BUILDER",0,0]
]

OSX 및 기타 BSD 플랫폼의 경우 다음을 시도하십시오.

sed -e x -e '$ {s/,$//;p;x;}' -e 1d  input

사용bash

while IFS=  read -r line
do
    [ "$a" ] && printf "%s\n" "$a"
    a=$b
    b=$line
done <input
printf "%s\n" "${a%,}"
printf "%s\n" "$b"

답변2

간단히 아래 Perl 한 줄짜리 명령을 시도해 볼 수 있습니다.

perl -00pe 's/,(?!.*,)//s' file

설명:

  • ,쉼표와 일치합니다.
  • (?!.*,)부정적 예측은 일치하는 쉼표 뒤에 쉼표가 없다고 주장합니다. 따라서 마지막 쉼표와 일치합니다.
  • s그리고 가장 중요한 것은 s개행 문자에도 일치하도록 점을 만드는 DOTALL 수정자입니다.

답변3

lcomma() { sed '
    $x;$G;/\(.*\),/!H;//!{$!d
};  $!x;$s//\1/;s/^\n//'
}

,그러면 입력 파일에서 마지막으로 나타나는 a만 제거되어야 하며 a가 ,발생하지 않는 파일도 계속 인쇄됩니다. 기본적으로 쉼표를 포함하지 않는 일련의 줄을 버퍼링합니다.

쉼표를 만나면 현재 줄 버퍼를 보류 버퍼로 바꾸고 마지막 쉼표 이후 발생한 모든 줄을 동시에 인쇄합니다.그리고보유 버퍼를 해제합니다.

방금 내 기록 파일을 뒤져보던 중에 다음과 같은 내용을 발견했습니다.

lmatch(){ set "USAGE:\
        lmatch /BRE [-(((s|-sub) BRE)|(r|-ref)) REPL [-(f|-flag) FLAG]*]*
"       "${1%"${1#?}"}" "$@"
        eval "${ZSH_VERSION:+emulate sh}"; eval '
        sed "   1x;     \\$3$2!{1!H;\$!d
                };      \\$3$2{x;1!p;\$!d;x
                };      \\$3$2!x;\\$3$2!b'"
        $(      unset h;i=3 p=:-:shfr e='\033[' m=$(($#+1)) f=OPTERR
                [ -t 2 ] && f=$e\2K$e'1;41;17m}\r${h-'$f$e\0m
                f='\${$m?"\"${h-'$f':\t\${$i$e\n}\$1\""}\\c' e=} _o=
                o(){    IFS=\ ;getopts  $p a "$1"       &&
                        [ -n "${a#[?:]}" ]              &&
                        o=${a#-}${OPTARG-${1#-?}}       ||
                        ! eval "o=$f;o=\${o%%*\{$m\}*}"
        };      a(){    case ${a#[!-]}$o in (?|-*) a=;;esac; o=
                        set $* "${3-$2$}{$((i+=!${#a}))${a:+#-?}}"\
                                ${3+$2 "{$((i+=1))$e"} $2
                        IFS=$;  _o=${_o%"${3+$_o} "*}$*\
        };      while   eval "o \"\${$((i+=(OPTIND=1)))}\""
                do      case            ${o#[!$a]}      in
                        (s*|ub)         a s 2 ''        ;;
                        (r*|ef)         a s 2           ;;
                        (f*|lag)        a               ;;
                        (h*|elp)        h= o; break     ;;
                esac;   done;   set -f; printf  "\t%b\n\t" $o $_o
)\"";}

실제로 꽤 좋습니다. 예, 를 사용 eval하지만 인수에 대한 숫자 참조 이외의 어떤 것도 전달하지 않습니다. sed마지막 일치 항목을 처리하기 위한 임의의 스크립트를 작성합니다 . 보여드리겠습니다:

printf "%d\" %d' %d\" %d'\n" $(seq 5 5 200) |                               
    tee /dev/fd/2 |                                                         
    lmatch  d^.0     \  #all re's delimit w/ d now                           
        -r '&&&&'    \  #-r or --ref like: '...s//$ref/...'      
        --sub \' sq  \  #-s or --sub like: '...s/$arg1/$arg2/...'
        --flag 4     \  #-f or --flag appended to last -r or -s
        -s\" \\dq    \  #short opts can be '-s $arg1 $arg2' or '-r$arg1'
        -fg             #tacked on so: '...s/"/dq/g...'                     

그러면 stderr에 다음이 인쇄됩니다. 다음은 lmatch님이 입력한 내용 의 사본입니다 .

5" 10' 15" 20'
25" 30' 35" 40'
45" 50' 55" 60'
65" 70' 75" 80'
85" 90' 95" 100'
105" 110' 115" 120'
125" 130' 135" 140'
145" 150' 155" 160'
165" 170' 175" 180'
185" 190' 195" 200'

함수의 evaled 하위 쉘은 모든 인수를 한 번 반복합니다. 이를 탐색하면서 각 스위치의 컨텍스트에 따라 적절하게 카운터를 반복하고 다음 반복을 위해 많은 인수를 건너뜁니다. 그때부터 인수당 몇 가지 작업 중 하나를 수행합니다.

  • 각 옵션에 대해 옵션 파서가 $a에 추가합니다 $o. 처리된 각 인수에 대해 인수 개수만큼 증가하는 $a값을 기준으로 할당됩니다 . 다음 두 값 중 하나가 할당됩니다. $i$a
    • a=$((i+=1))- 짧은 옵션에 인수가 추가되지 않거나 옵션이 긴 경우에 할당됩니다.
    • a=$i#-?- 옵션이 짧은 경우에 할당됩니다.하다인수가 추가되어 있습니다.
    • a=\${$a}${1:+$d\${$(($1))\}}- 초기 할당에 관계없이 $a의 값은 항상 중괄호로 묶이고 경우에 따라 -s때로는 $i하나 더 증가하고 추가로 구분된 필드가 추가됩니다.

결과적으로 eval알 수 없는 내용이 포함된 문자열이 전달되지 않습니다. 각 명령줄 인수는 숫자 인수 번호로 참조됩니다. 첫 번째 인수의 첫 번째 문자에서 추출된 구분 기호도 이스케이프되지 않은 문자를 사용해야 하는 유일한 경우입니다. 기본적으로 이 함수는 매크로 생성기입니다. 인수의 값을 특별한 방식으로 해석하지 않습니다 sed.(물론 그럴 것이다)스크립트를 구문 분석할 때 이를 쉽게 처리할 수 있습니다. 대신, 인수를 실행 가능한 스크립트로 현명하게 배열합니다.

다음은 작동 중인 함수의 디버그 출력입니다.

... sed "   1x;\\$2$1!{1!H;\$!d
        };      \\$2$1{x;1!p;\$!d;x
        };      \\$2$1!x;\\$2$1!b
        s$1$1${4}$1
        s$1${6}$1${7}$1${9}
        s$1${10#-?}$1${11}$1${12#-?}
        "
++ sed '        1x;\d^.0d!{1!H;$!d
        };      \d^.0d{x;1!p;$!d;x
        };      \d^.0d!x;\d^.0d!b
        sdd&&&&d
        sd'\''dsqd4
        sd"d\dqdg
        '

따라서 lmatch파일의 마지막 일치 항목 이후 데이터에 정규식을 쉽게 적용하는 데 사용할 수 있습니다. 위에서 실행한 명령의 결과는 다음과 같습니다.

5" 10' 15" 20'
25" 30' 35" 40'
45" 50' 55" 60'
65" 70' 75" 80'
85" 90' 95" 100'
101010105dq 110' 115dq 120'
125dq 130' 135dq 140sq
145dq 150' 155dq 160'
165dq 170' 175dq 180'
185dq 190' 195dq 200'

...마지막으로 /^.0/일치하는 파일 입력의 하위 집합이 주어지면 다음 대체가 적용됩니다.

  • sdd&&&&d- $match자기 자신으로 4번 교체됩니다.
  • sd'dsqd4- 마지막 일치 이후 줄 시작 부분 다음에 나오는 네 번째 작은따옴표입니다.
  • sd"d\dqd2- 마찬가지지만 큰따옴표와 전 세계적으로 사용됩니다.

따라서 lmatch파일에서 마지막 쉼표를 제거하는 방법을 보여주기 위해 다음을 수행합니다.

printf "%d, %d %d, %d\n" $(seq 5 5 100) |
lmatch '/\(.*\),' -r\\1

산출:

5, 10 15, 20
25, 30 35, 40
45, 50 55, 60
65, 70 75, 80
85, 90 95 100

답변4

보다https://stackoverflow.com/questions/12390134/remove-comma-from-last-line

이것은 나를 위해 일했습니다 :

$cat input.txt
{"name": "secondary_ua","type":"STRING"},
{"name": "request_ip","type":"STRING"},
{"name": "cb","type":"STRING"},
$ sed '$s/,$//' < input.txt >output.txt
$cat output.txt
{"name": "secondary_ua","type":"STRING"},
{"name": "request_ip","type":"STRING"},
{"name": "cb","type":"STRING"}

가장 좋은 방법은 마지막 줄을 제거하고 쉼표를 제거한 후 ] 문자를 다시 추가하는 것입니다.

관련 정보