파일에서 빈 줄 잘라내기(bash 스크립트)

파일에서 빈 줄 잘라내기(bash 스크립트)

파일의 모든 빈 줄을 제거하려고 하는데, 비어 있지 않은 각 줄 뒤에 "\n"을 유지하고 싶습니다.

문제: CLI에서 사용하면 명령이 제대로 작동하지만 bash 스크립트에서 명령을 사용할 때마다 모든 "\n"이 제거되므로 모든 결과를 별도의 줄에 넣는 대신 한 줄에 넣습니다.

이것은 내 코드입니다.

#printing second and third word from every line and remove lines that do not contain any digits
    result=$(cat "$output_file" | awk '{print $2" "$3}' | sed 's/[^0-9]*/\\n/')
    echo -e ""$result"" > "$output_file"

#getting rid of all empty lines but what happens is that the whole file becomes one line
    no_empty_lines=$(cat "$output_file" | awk NF)
    echo -e ""$no_empty_lines"" > "$output_file"

편집할 파일:

> 135.121.62.246 7.4
> 135.121.160.65 7.8
> 135.121.106.56 7.5
>  
>  
> 135.121.106.96 6.2
>  
>  
> 135.121.160.106 10
>   
> 135.121.90.46 명령 실패

요청된 결과:

편집할 파일:

> 135.121.46.246 7.4
> 135.121.106.46 7.8
> 135.121.106.56 7.5
> 135.121.106.96 6.2  
> 135.121.160.16 10
> 135.121.90.46 명령 실패

답변1

하나 이상의 문자가 포함된 행을 일치시킬 수 있습니다.

grep . {file}

관련 파일을 대체하는 코드에 넣으십시오. 임시 파일을 생성하고 생성에 성공하면 원본 파일을 임시 파일로 바꿉니다. 마지막으로 원본 파일을 성공적으로 교체하지 못한 경우 임시 파일을 삭제합니다.

file=some_file.txt
grep . "$file" >"$file.tmp.$$" && mv -f "$file.tmp.$$" "$file"
rm -f "$file.tmp.$$"

그런데 이것이 원래 코드에서 개행 문자가 손실되는 이유입니다.

result=$(cat "$output_file" | awk '{print $2" "$3}' | sed 's/[^0-9]*/\\n/')
echo -e ""$result"" > "$output_file"

변수 $result에 줄 바꿈을 포함하여 텍스트가 올바르게 포함되어 있습니다. (이것은 비효율적인 생산 라인이지만 작동하는 동안 우리는 그 문제를 무시합니다.)

그런데 이 echo줄이 정말 이상해요. 당신이 거기 있는 이유를 이해할 수 없습니다 "". 길이가 0인 따옴표로 묶인 문자열을 나타내며 다음과 같이 효과적으로 제거할 수 있습니다.

echo -e $result > "$output_file"

그런 다음 쉘은 내용을 평가 $result하고 공백 문자열을 단일 공백으로 변환합니다. 이 경우 탭개행 문자공백으로 처리됩니다. ( hello whole\nworld로 읽으세요 hello whole world.)

변수를 큰따옴표로 묶으면 이 문제가 발생하지 않습니다.

echo -e "$result" > "$output_file"

답변2

귀하의 코드가 개선되었습니다:

awk -i inplace '$2 ~ /[0-9]/ || $3 ~ /[0-9]/ { print $2, $3 }' "$output_file"

awk이는 GNU 4.1.0 이상(이 옵션의 경우 ) 을 사용한다고 가정합니다 -i inplace. 이 코드는 필드 중 하나 이상에 숫자가 포함된 행에서 두 번째 및 세 번째 필드를 추출합니다.

GNU 없이 awk:

tmpfile=$(mktemp)
cp "$output_file" "$tmpfile"
awk '$2 ~ /[0-9]/ || $3 ~ /[0-9]/ { print $2, $3 }' "$tmpfile" >"$output_file"
rm -f "$tmpfile"

이 프로그램을 다르게 표현하는 방법은 두 번째와 세 번째 필드를 awk재설정한 $0다음 숫자를 테스트하는 것입니다.

awk -i inplace '{ $0 = $2 " " $3 }; /[0-9]/' "$output_file"

코드에 많은 문제가 있습니다. 당신이 직접 언급한 것, 모든 줄이 한 줄로 끝나는 것은 $result인용되지 않은 값을 사용하기 때문입니다 echo. $result어떤 이유로든 확장의 양쪽에 두 개의 큰따옴표(두 개의 빈 문자열)를 사용하고 있기 때문에 확장에 따옴표가 없습니다 ""$result"".

따옴표 없이 변수 확장을 사용하면 쉘은 변수 값을 가져와 공백, 탭 또는 줄 바꿈으로 분할하여 여러 단어를 만듭니다. 그러면 각 단어에 파일 이름이 와일드카드로 추가됩니다. 그런 다음 생성된 단어는 echo -e각 인수 사이에 공백이 있고 끝에 개행 문자가 있는 각 인수를 출력하는 코드에서 사용됩니다.

또한 명령의 출력을 변수에 넣을 필요가 없습니다. 이 경우에는 파일로 리디렉션하기만 하면 됩니다.

명령은 sed각 줄의 시작 부분에 문자열을 삽입하여 \n줄의 첫 번째 줄에 있는 숫자가 아닌 모든 항목을 대체합니다. 숫자가 포함되지 않은 행은 삭제되지 않습니다. 이렇게 하려면 sed표현식을 사용하십시오 /[0-9]/!d. 그러나 숫자가 포함된 스크립트 줄만 출력하는 한 awk(위의 코드에서 수행하는 작업) 이 작업을 수행할 필요가 없습니다.

놀랍게도 배관 입력 awk이나 sed그 반대의 경우는 그리 흔하지 않습니다. 할 일 이 충분합니다 awk.sed

답변3

코드의 문제는 결과를 bash변수에 저장한다는 것입니다.

 no_empty_lines=$(cat "$output_file" | awk NF)

그 중 (중복을 건너뛰는 cat) 다음과 같이 볼 수 있습니다.

 result=$(command that returns multi-line data)

그러나 bash여러 줄 문자열을 공백이 포함된 한 줄로 변환하세요.

가능한 방법은 다음과 같습니다여기- 이것이 당신에게 필요한 것이라고 생각하지만 다음을 사용하십시오 bash.

 no_empty_lines=( $(awk 'NF' "$output_file") )

현재 항목은 ${no_empty_lines[0]}, ${no_empty_lines[1]}, ... 입니다.

루프로 호출

 for ((i=0;i<=${#no_empty_lines[@]}-1;i++)) ; do echo ${no_empty_lines[i]} ; done

다시 말하지만 이는 코드가 실패하는 이유를 보여주기 위한 것입니다 bash. 위 스레드의 옵션 중 하나를 사용하는 것이 좋습니다.반품: 이 배열은 모든 단어를 배열의 별도 요소에 배치하므로 입력의 개행 구조가 완전히 제거됩니다.

답변4

@roaima의 도움으로 문제를 좁힐 수 있었고,

귀하의 답변에서 결과는 여러 행의 데이터를 올바르게 저장합니다. 인쇄할 때 문제가 발생합니다. 변수가 인용되지 않았기 때문에(rcho ""$result""는 echo $result 와 동일함) 쉘이 결과를 여러 단어로 구문 분석하고 개행 문자는 다른 공백처럼 처리됩니다. – Emma 루오 6시간 전

따라서 가능한 해결책은 다음과 같습니다.

result=$(cat "$output_file"| awk '{print $2" "$3}' | sed 's/[^0-9]*//')
echo -e "$result" | awk NF > "$output_file"

변수가 올바르게 저장되었다고 가정하고 "$result"를 에코한 다음 "awk NF"로 파이핑하여 빈 줄을 제거하고 파일로 출력할 때 추가 따옴표를 제거했습니다.

이제 결과는 다음과 같습니다.

> 135.121.9.256 6.2
> 135.121.160.50 7.5
> 135.121.106.10 10
> 135.121.9.66 명령 실패
> 135.121.100.156 명령 실패

관련 정보