bash를 사용하여 디렉토리에 모든 csv 파일의 처음 200개 행을 유지하는 방법은 무엇입니까?

bash를 사용하여 디렉토리에 모든 csv 파일의 처음 200개 행을 유지하는 방법은 무엇입니까?

수천 개의 행이 포함된 약 50개의 매우 큰 csv 파일이 있습니다.

각 파일의 처음 200줄만 유지하고 싶습니다. 생성된 파일이 원본 파일을 덮어쓰더라도 문제가 없습니다.

이 작업을 수행하려면 어떤 명령을 사용해야 합니까?

답변1

현재 디렉터리에 모든 CSV 파일이 포함되어 있고 모두 .csv파일 이름 접미사가 있다고 가정합니다.

for file in ./*.csv; do
    head -n 200 "$file" >"$file.200"
done

head그러면 리디렉션을 사용하여 각 CSV 파일의 처음 200개 행이 새 파일로 출력됩니다. 새 파일의 이름은 이전 파일과 동일하지만 .200이름 끝에 추가됩니다. 새 파일 이름이 이미 존재하는지 여부는 확인하지 않습니다.

원래 것을 교체하고 싶다면:

for file in ./*.csv; do
    head -n 200 "$file" >"$file.200" &&
    mv "$file.200" "$file"
done

명령 &&끝에 는 실행 중 문제가 있으면 실행되지 않음 head을 의미합니다 .mvhead

CSV 파일이 현재 디렉터리 내의 하위 디렉터리에 흩어져 있는 경우 shopt -s globstar루프의 패턴을 로 바꾸십시오. 그러면 현재 디렉터리 안이나 아래에 있는 모든 CSV 파일을 찾아 각 파일에 대해 작업을 수행합니다. 와일드카드 패턴은 "재귀적으로" 하위 디렉터리와 일치하지만 셸 옵션이 설정된 경우에만 해당됩니다../*.csv./**/*.csv**globstar


줄 바꿈이 포함된 데이터가 포함된 CSV 파일의 경우 레코드가 잘릴 수 있으므로 위 방법이 제대로 작동하지 않습니다. 대신 일부 CSV 인식 도구를 사용하여 작업을 수행해야 합니다.

다음은 CSV 파일을 구문 분석하고 일반적으로 처리하기 위한 명령줄 도구 세트인 CSVkit과 jqJSON 파일을 처리하기 위한 도구를 사용합니다.

CSV 제품군에는 특정 지점에서 CSV 파일을 자를 수 있는 도구가 없지만, CSV 파일을 JSON으로 변환하고 이를 사용하여 jq처음 200개의 레코드만 출력할 수 있습니다.

for file in ./*.csv; do
    csvjson -H "$file" | jq -r '.[:200][] | map(values) | @csv' >"$file.200" &&
    mv "$file.200" "$file"
done

아래의 짧은 예와 같이 일부 CSV 파일이 주어지면

a,b,c
1,2,3
"hello, world",2 3,4
"hello
there","my good
man",nice weather for ducks

csvjson명령은 생성됩니다

[
  {
    "a": "a",
    "b": "b",
    "c": "c"
  },
  {
    "a": "1",
    "b": "2",
    "c": "3"
  },
  {
    "a": "hello, world",
    "b": "2 3",
    "c": "4"
  },
  {
    "a": "hello\nthere",
    "b": "my good\nman",
    "c": "nice weather for ducks"
  }
]

그런 다음 도구 jq는 이 데이터를 가져와 배열의 각 개체(처음 200개 개체만)에 대해 값을 배열로 추출하고 이를 CSV로 형식화합니다.

CSVkit의 다른 도구를 사용하여 이 변환을 직접 수행하는 것이 가능할 수도 있지만 csvpyPython 기술이 없기 때문에 이를 달성하기 위한 솔루션을 찾지는 않겠습니다.

답변2

이전 답변은 데이터를 복사하고 파일을 덮어씁니다. 이 기술은 동일한 inode를 유지하고 복사하지 않으며 훨씬 빠르게 실행되어야 합니다. 각 파일에 대해 다음을 수행합니다.

(a) 처음 200줄을 읽어 각 파일의 길이를 구합니다.

truncatetruncate(b) GNU coreutils 또는 일부 BSD 시스템의 명령을 사용하여 파일을 이 길이로 자릅니다 .

SZ="$( head -n 200 -- "${file}" | wc -c )"
truncate -s "${SZ}" -- "${file}"

답변3

쉘 와일드카드와 함께 sed를 사용하십시오:

sed -ni '1,200p' *.csv

globbing/sed/병렬을 사용하십시오.

printf '%s\n' *.csv | parallel -- sed -ni '1,200p' {}

.csv해당 디렉토리의 모든 파일을 찾습니다.현재 디렉터리GNU Parallel에 공급하면 처음 200줄만 유지하도록 sed됩니다. 이렇게 하면 현재 위치의 파일을 덮어쓰게 됩니다.

또는 병렬 헤더를 사용하십시오.

printf '%s\n' *.csv | parallel -- head -n 200 {} ">" {}.out

.out그러면 접미사가 포함된 새 파일이 생성됩니다 .

답변4

저는 비교적 초보라서 부드럽게 대해주세요. 제가 제안한 솔루션이 최적이 아닌 경우 건설적인 피드백을 보내주시면 감사하겠습니다.

예를 들어 1부터 4까지 번호가 매겨진 4개의 샘플 파일을 만들었습니다. touch {1..4}각 파일에는 첫 번째 파일의 11~20행과 같이 10개의 샘플 라인이 포함되어 있습니다.

파일 1

Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
Line 7
Line 8
Line 9
Line 10 

파일 2

Line 11
Line 12
Line 13
Line 14
Line 15
Line 16
Line 17
Line 18
Line 19
Line 20

추출의 처음 2줄(200으로 추론 가능)을 예로 들면 이 명령은 head -n 2 {1..4}출력을 반환합니다.

==> 1 <==
Line 1
Line 2

==> 2 <==
Line 11
Line 12

==> 3 <==
Line 21
Line 22

==> 4 <==
Line 31
Line 32

이 명령은 다음 명령을 사용하여 출력을 다른 파일로 리디렉션할 수 있습니다.head -n 2 {1..4} > ExtractedOutput

관련 정보