![sed를 사용하여 텍스트 파일에서 여러 임의의 줄을 삭제하는 방법은 무엇입니까?](https://linux55.com/image/77886/sed%EB%A5%BC%20%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC%20%ED%85%8D%EC%8A%A4%ED%8A%B8%20%ED%8C%8C%EC%9D%BC%EC%97%90%EC%84%9C%20%EC%97%AC%EB%9F%AC%20%EC%9E%84%EC%9D%98%EC%9D%98%20%EC%A4%84%EC%9D%84%20%EC%82%AD%EC%A0%9C%ED%95%98%EB%8A%94%20%EB%B0%A9%EB%B2%95%EC%9D%80%20%EB%AC%B4%EC%97%87%EC%9E%85%EB%8B%88%EA%B9%8C%3F.png)
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 NNd
NN은 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
행을 색인화하고, 두 번째는 grep
80개의 행을 무작위로 선택하고 sed
처음 추가된 행 번호를 제거합니다 grep
.
shuf
참고: 출력 순서가 필요하지 않은 경우 마지막 출력을 파이프하십시오.