매우 큰 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]
]
사용 awk
및bash
$ 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'
함수의 eval
ed 하위 쉘은 모든 인수를 한 번 반복합니다. 반복하면서 각 스위치의 컨텍스트에 따라 카운터를 적절하게 반복하고 다음 반복을 위해 많은 매개변수를 건너뜁니다. 그 시점부터 각 인수에 대해 다음 작업 중 하나를 수행합니다.
- 각 옵션에 대해 옵션 구문 분석기는 처리된 각 인수의 값을 기준으로 인수 수의 증분으로 .allocation
$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'
...파일 input 의 마지막 일치 하위 집합을 고려하여 /^.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"}
가장 좋은 방법은 마지막 줄을 제거하고 쉼표를 제거한 후 ] 문자를 다시 추가하는 것입니다.