ファイルから空白行を切り取る(bashスクリプト)

ファイルから空白行を切り取る(bashスクリプト)

ファイル内のすべての空行を削除しようとしていますが、空でない各行の後に「\ n」を保持したいと思います。

問題:CLIで使用するとコマンドは正常に機能しますが、bashスクリプトでコマンドを使用するたびにすべての「\ n」が削除されるため、すべての結果を別々の行に置くのではなく1行に入れます。

これは私のコードです。

#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

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。このコードは、1つ以上のフィールドに数字を含む行から2番目と3番目のフィールドを抽出します。

GNUなしawk

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

このプログラムを異なる方法で表現する方法は、2番目と3番目のフィールドをawkリセットして$0から数字をテストすることです。

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

コードには多くの問題があります。あなたが直接言及したもの、すべての行が1行で終わるのは、引用符で囲まれてい$resultない値を使用するためですecho$result何らかの理由で拡張の両側に2つの二重引用符(2つの空の文字列)を使用しているため、拡張に引用符はありません""$result""

引用符なしで変数拡張を使用すると、シェルは変数値を取得し、スペース、タブ、または改行に分割して複数の単語を作成します。これにより、各単語にファイル名がワイルドカードとして追加されます。その後、生成された単語は、各引数echo -eの間にスペースがあり、末尾に改行文字を持つ各引数を出力するコードで使用されます。

また、コマンドの出力を変数に入れる必要はありません。この場合は、ファイルにリダイレクトするだけです。

コマンドは、sed各行の先頭に文字列を挿入して、行\nの最初の行にある数字以外のすべての項目を置き換えます。数字を含まない行は削除されません。これを行うには、sed式を使用してください/[0-9]/!d。ただし、数値を含むスクリプト行のみを出力する限りawk(上記のコードで実行する操作)、これを行う必要はありません。

驚くべきことに、配管入力awksedその逆の場合はそれほど一般的ではありません。やることは十分ですawksed

答え3

コードの問題は、結果をbash変数に保存することです。

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

その中(重複をスキップするcat)は次のように見えます。

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

ただし、bash複数行の文字列をスペースを含む1行に変換してください。

可能な方法は次のとおりです。ここ- これがあなたに必要なものだと思いますが、以下を使用してください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。上記のスレッドのオプションの1つを使用することをお勧めします。返品:この配列はすべての単語を配列の別の要素に配置するため、入力の改行構造が完全に削除されます。

答え4

@roaimaの助けを借りて問題を絞り込むことができ、

あなたの答えでは、結果は複数行のデータを正しく保存します。印刷すると問題が発生します。変数が引用されていないため(rcho ""$result""はecho $resultと同じです)、シェルは結果を複数の単語に解析し、改行文字は他の空白のように扱われます。 – Emma Luo 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 コマンドの失敗

関連情報