파일의 모든 빈 줄을 제거하려고 하는데, 비어 있지 않은 각 줄 뒤에 "\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 명령 실패