다음 형식의 CSV 파일이 여러 개 있습니다.
"TIMESTAMP",col2,col3,col4
"yyyy-mm-dd HH:mm",20,19,17
나는 결국 다음과 같이 -
교체 하고 싶습니다 ./
TIMESTAMP,col2,col3,col4
yyyy/mm/dd HH:mm,20,19,17
다음 명령을 사용하여 파일을 첨부했지만 아무 일도 일어나지 않습니다.
find -name '*.csv' -exec awk '{gsub(/-/, "/",$1)}' '{}' \;
내가 무엇을 놓치고 있나요? 도와주세요
답변1
find . -name '*.csv' -type f -size +10c -exec perl -pi -e '
s{^(\d\d\d\d)-(\d\d)-(\d\d)\b}{$1/$2/$3}' {} +
-
줄 시작 부분의 타임스탬프에 있는 s 만 대체되고 다른 모든 -
이벤트는 무시됩니다.
.csv
해당 타임스탬프가 포함되지 않은 파일도 포함하여 모든 파일을 대체합니다 . 이를 방지하려면 GNU를 사용하여 grep
다음을 수행할 수 있습니다.
grep -rlPZ --include='*.csv' '^\d\d\d\d-\d\d-\d\d\b' . |
xargs -r0 perl -pi -e '
s{^(\d\d\d\d)-(\d\d)-(\d\d)\b}{$1/$2/$3}' {} +
답변2
명령 은 awk
실제로 원하는 변경을 수행하지만(쉼표로 구분된 필드 대신 첫 번째 공백으로 구분된 필드를 변경하는 경우 제외) 인쇄하라고 지시하지 않았기 때문에 인쇄되지 않습니다.
$ cat file.csv
TIMESTAMP,col2,col3,col-4
yyyy-mm-dd HH:mm,20,19,17
$ awk '{gsub(/-/, "/",$1)}' file.csv
$
위에서 볼 수 있듯이 명령에는 출력이 없습니다. 비교:
$ awk -F, -v OFS=, '{gsub(/-/, "/", $1); print}' file.csv
TIMESTAMP,col2,col3,col-4
yyyy/mm/dd HH:mm,20,19,17
그러나 이는 단순히 모든 파일의 내용을 표준 출력으로 인쇄하기 때문에 원하는 결과가 아닐 수 있습니다. 실제 파일을 수정하려면 다음을 시도하십시오.
$ perl -i -F, -lane '$F[0] =~ s|-|/|g; print join ",",@F' file.csv
$ cat file.csv
TIMESTAMP,col2,col3,col4
yyyy/mm/dd HH:mm,20,19,17
만일을 대비해 -i.bak
확장자를 가진 원본 파일의 복사본을 만들어 사용하는 것이 좋습니다 . .bak
그런 다음 이를 다음과 같이 명령에 통합할 수 있습니다.
find . -name '*.csv' -type f -exec perl -i.bak -F, -lane '
$F[0] =~ y|-|/|; print join ",", @F' '{}' +
또는 GNU awk( )가 있고 gawk
현재 작업 디렉터리에 infile
또는 이름의 파일이 포함되어 있지 않다는 것을 보장할 수 있는 infile.awk
경우 다음을 수행할 수 있습니다.
find . -name '*.csv' -type f -exec gawk -F, -v OFS=, -i inplace '
{gsub(/-/, "/",$1); print}' '{}' +
답변3
질문에 표시된 예시 입력과 예상 출력을 귀하가 말한 내용과 병합하세요.코멘트타임스탬프 값에 실제로 어떤 일이 발생합니까?
$ cat foo.csv
"TIMESTAMP",col2,col3,col4
""yyyy-mm-dd HH:mm"",20,19,17
그런 다음 GNU awk를 사용하여 다음을 수행하십시오 -i inplace
.
$ find . -name 'foo.csv' -exec awk -i inplace '{gsub(/"/,""); gsub(/-/,"/"); print}' {} +
$ cat foo.csv
TIMESTAMP,col2,col3,col4
yyyy/mm/dd HH:mm,20,19,17
또는 GNU awk 스크립트(for -i
)를 다음 GNU sed 스크립트로 바꿀 수 있습니다.
sed -i 's:"::g; s:-:/:g'
"
s 또는 s를 다른 곳에서 바꾸고 싶지 않고 -
참조 필드 내에 "
s, s 또는 개행 문자가 없는 경우 ,
awk 스크립트를 다음과 같이 변경하세요.
BEGIN{FS=OFS=","} {gsub(/"/,"",$1); gsub(/-/,"/",$1); print}
답변4
사용행복하다(이전 Perl_6)
간단한 방법:
~$ raku -pe 's:g{ \w**4 <( (\-) (\w**2) (\-) )> \w**2 } = "/$1/";' file
CSV 콘텐츠 검증:
~$ raku -MText::CSV -e 'my @a = csv(in => $*IN, sep => ","); \
@a>>.[0] = @a>>.[0].map: \
*.subst(:global, / \w**4 <( (\-) (\w**2) (\-) )> \w**2 /, {"/$1/"} ); \
csv(in => @a, out => $*OUT, sep => ",");' < file
다음은 Perl 계열의 프로그래밍 언어인 Raku로 작성한 답변입니다. 첫 번째 답변은 익숙한 s///
대체 관용구를 사용하지만 여기서 Raku는 새로운 형식 옵션을 추가했습니다: s{original} = "replacement"
. 문자/숫자 및 대시(하이픈)의 올바른 조합과 일치하는 항목을 찾는 Raku의 <(…)>
캡처 플래그는 원하는 블록 외부의 모든 항목을 제거하는 데 사용되며 이는 교체 시 변경됩니다.
두 번째 답변은 Raku의 Text::CSV
모듈을 사용하여 CSV 입력/출력을 검증합니다. 샘플 데이터만 사용첫번째 줄대체됩니다(이 @a>>.[0]
관용어는 데이터의 첫 번째 열에만 해당됩니다).
입력 예:
"TIMESTAMP",col2,col3,col4
"yyyy-mm-dd HH:mm",20,19,17
출력 예(첫 번째 코드 예):
"TIMESTAMP",col2,col3,col4
"yyyy/mm/dd HH:mm",20,19,17
출력 예(두 번째 코드 예, CSV 출력 확인):
TIMESTAMP,col2,col3,col4
"yyyy/mm/dd HH:mm",20,19,17
Text::CSV
이를 변경해야 하는 경우 Raku 모듈에는 출력 열을 참조하기 위한 다양한 옵션이 있습니다(기본값은 공백이 포함된 열 단위 요소를 참조하는 것입니다). 쉘 글로빙에 의존하지 않고 코드 본문에서 입력을 얻을 수도 있습니다. csv(in => $*IN, sep => ",");
코드 부분을 다음과 같이 변경 하십시오 .
csv(in => "path/to/file", sep => ",");
https://raku.land/zef:Tux/Text::CSV
https://docs.raku.org/routine/dir
https://raku.org