sed를 사용하여 텍스트 파일에서 여러 임의의 줄을 삭제하는 방법은 무엇입니까?

sed를 사용하여 텍스트 파일에서 여러 임의의 줄을 삭제하는 방법은 무엇입니까?

90줄 텍스트 파일에서 임의의 10줄을 삭제하고 새 파일로 출력하고 싶습니다. 나는 이 작업을 위해 sed를 사용하려고 노력해 왔지만 두 가지 문제가 있습니다. 나는 다음을 사용하고 있습니다 :

sed -i $((1 + RANDOM & 90))d input.txt > output.txt

그런 다음 명령을 10번 실행합니다(더 좋은 방법이 있을 것 같습니다!).

내가 겪는 첫 번째 문제는 오류가 발생한다는 것입니다.

sed: -e 표현식 #1, char 2: 라인 주소 0의 사용이 잘못되었습니다.

나는 이것이 행 1을 삭제하고 다시 시도하고 있다는 사실과 관련이 있다고 생각합니다.

두 번째 문제는 동일한 명령을 사용하기 전에는 작동했지만 출력 파일에 아무 것도 기록되지 않는 경우가 있다는 것입니다.

답변1

RANDOM % 90대신 을 사용하고 싶을 수도 있습니다 &. 여기서 0이 나옵니다(행 1을 삭제하면 다음 실행 시 행 번호가 1 .. 89로 지정됩니다).

하지만 문제가 있습니다. 수식은 동일한 숫자를 여러 번 생성할 수 있습니다. 이를 방지하려면 다른 접근 방식을 사용하십시오. 즉, 숫자를 뒤섞어 상위 10개를 선택하십시오.

shuf -i1-90 -n10 | sed 's/$/d/' | sed -f- input > output

sed생성 스크립트가 마음에 들지 않으면 sed다음을 사용할 수도 있습니다 printf.

sed -f <( printf %dd\;  $(shuf -i1-90 -n10) ) input > output

답변2

이식 가능한 GNU가 없다면 shuf다음과 같이 할 수 있습니다:

awk -v n=90 -v p=10 '
  BEGIN {srand()}
  rand() * n-- < p {p--; next}
  {print}' < file

p또한 shuf+sed는 o(n)에 있고 shuf+sed는 o(n*p)에 있으므로 값이 높은 shuf+sed 방법보다 더 효율적입니다 . n=1000000일 때 내 시스템의 중단점은 GNU sed 대 GNU awk의 경우 약 p=35이고, GNU sed 대 mawk의 경우 p=1 정도입니다(mawk에서는 항상 더 빠르기 때문입니다).

답변3

여기서의 과제는 90개 행 중 하나를 삭제한 다음 나머지 89개 행 중 하나를 삭제하는 것입니다. 89개 행만 남아 있으면 90번째 행을 삭제할 수 없습니다.

eval $(for i in {90..81}; do CMD="$CMD | sed $(( (RANDOM % $i)+1 ))d"; done; echo cat infile $CMD) > outfile

for 루프는 일련의 문자열을 누적하여 파이프라인을 형성합니다. 여기서 | sed NNdNN은 1에서 90까지 시작하고 1에서 81까지 끝나는 축소 범위의 난수이며 결과는 다음과 같습니다.| sed 88d | sed 12d | sed 36d...

CMD 명령이 형성된 후 이를 cat infile파이프라인 CMD 앞에 추가합니다(CMD는 |for 루프에서 a로 시작합니다). CMD는 이제 다음과 같습니다cat infile | sed 88d | sed 12d...

마지막으로 eval명령의 CMD 문자열을 실행하고 결과를outfile

답변4

성능에 문제가 없으면 다음을 사용할 수 있습니다.

cat PATH_OF_SOURCE_FILE | \
grep -n ^ | \
grep -E "^($(seq 1 90 | shuf | head -n 80 | paste -s -d '|')):" | \
sed 's/[0-9]*:\(.*\)$/\1/' > PATH_TO_TARGET_FILE

첫 번째는 grep행을 색인화하고, 두 번째는 grep80개의 행을 무작위로 선택하고 sed처음 추가된 행 번호를 제거합니다 grep.

shuf참고: 출력 순서가 필요하지 않은 경우 마지막 출력을 파이프하십시오.

관련 정보