次のような変数があります。
$ echo "$LIST"
file1: ok
file2: ok
file3:
file4:
file5: ok
その後、異常なファイルのリストをインポートする必要があります。
$ sed '/:\s.\+$/d' <<< "$LIST"
file3:
file4:
ファイルは有効ですが、リストに異常なファイルがない場合は、次のことが発生します。
$ echo "$LIST"
file1: ok
file2: ok
file3: ok
file4: ok
file5: ok
$ sed '/:\s.\+$/d' <<< "$LIST"
$ NEWLIST=$(sed '/:\s.\+$/d' <<< "$LIST")
$ echo "$NEWLIST"
$ cat -A <<< "$NEWLIST"
$
$ wc -l <<< "$NEWLIST"
1
$ wc -c <<< "$NEWLIST"
1
この変数に追加された改行文字(\ nのようです)は、ファイルがwc -l
いくつあるかを知るために使用されるため、ファイルがリストされていると識別するため、私のプログラムを混乱させます。 \ nがbashまたはsedによって割り当てられたかどうかは完全にはわかりません。誰もが解決策を知っていますか?
答え1
アイテムのみを除外する場合は、ok
次のことができます。
grep -cv ': ok$' <<< "$LIST"
または似ていますが、ほぼ反対です。
grep -c ':$' <<< "$LIST"
編集:@ilkkachuのコメントに基づいて
リストが完全に空の場合は、-vc
いくつかの動作のためにバリアントが1という数を誤って報告します<<<
。
空のリストを検出するためにガードを追加するか、単にパイプを使用することができます。
printf "%s" "$LIST" | grep -vc ": ok$"
リストに空白行が含まれていると、使用時に計算エラーが発生する可能性があります-vc
。
いずれの場合も、誤った計算を防止するために更なる修正を行うことができる。
grep -vcE "^$|: ok$"
しかし今、私たちはコードを理解するのが難しくなり始めます。
答え2
Here-stringは<<<
文字列をコマンドに渡す前に文字列の末尾に改行文字を追加しますが、コマンド置換は内部コマンドの出力を読み取った後に末尾の改行文字を削除します。
また、echo
印刷内容に末尾の改行文字が追加されますが、ここではこれは主な問題ではありません。
したがって、変数に末尾に改行文字を含む完全な行があると仮定すると、文字列は次のようになります。file1: ok<nl>
sed '/ok/d' <<< "$LIST"
ここで実行してsed
入力を受け取りますfile1: ok<nl><nl>
。含まれている行をすべて削除し、ok
空白行を出力します<nl>
。
末尾の改行を削除し、空の文字列を提供するコマンド置換を使用してこれをキャッチできます。次に、に割り当てますNEWLIST
。
echo "$NEWLIST"
改行文字が印刷され(echo
1つが追加されたため)、改行wc -l <<< "$NEWLIST"
文字が入力として提供されますwc
(here-stringに1が追加されたため)。
変数が元の just で末尾の改行file1: ok
がない場合、コマンドの置換だけでは sed 出力の末尾から改行が削除されず、同じ最終結果が得られます。
これが意味するのは、ここでコマンド置換と文字列がほとんど1行の値で動作することです。変数に改行文字が表示されることを望まないかもしれませんが、一般的には、コマンドに行全体を入力として提供したいということです。見てわかるように、複数行の文字列にも機能しますが(最後の改行が変数から欠落している場合)、奇妙な改行の削除と追加がまだ発生します。削除する改行がないと、競合が発生します。
このジャグリングを実行する理由を理解するには、コマンド置換がhere出力から改行文字を削除しなかった場合、末尾のdate
ピリオドの前に改行文字が印刷され、途中で行が途切れることに注意してください。
$ weekday=$(date +%A)
$ echo "today is a $weekday."
today is a Thursday.
最も簡単な解決策は、おそらく複数行のデータをファイルに保存することです。 5行が含まれていますinputfile
(適切な改行を含む)。
file1: ok
file2: ok
file3: ok
file4: ok
file5: ok
それから:
tmpfile=$(mktemp)
sed -e '/ok/d' < inputfile > "$tmpfile"
wc -l < "$tmpfile"
rm -f "$tmpfile"
出力0
。
(標準のPOSIXネイティブまたは拡張正規表現構文では\s
ないか、どちらも\+
ないため、macOSなどのすべてのシステムでは機能しませんsed
。これが/ok/
上記で使用した理由です。)
答え3
\ nがbashまたはsedによって割り当てられたかどうかは完全にはわかりません。
現在はどちらもありません。たとえば、確認できます。
$ echo -n "$NEWLIST" # echo without -n adds a newline
$ wc -l <<< ""
1
$ wc -c <<< ""
1
変数(空)を印刷して新しい行で終わるように意図されていますecho
。この文字列の場合、Bashは最後の行が\ nで終わらないとツールが奇妙に動作する傾向があるため、新しい行で終わることを確認します。
おそらくこの問題を解決する最も簡単な方法は、NEWLISTが空であることを確認することです。または、ファイルを使用してより直接作業することもできます。たとえば、
list_file="$(mktemp)"
new_list_file="$(mktemp)"
# cleanup
trap 'rm "$list_file" "$new_list_file"' EXIT
echo "$LIST" > "$list_file"
sed '/:\s.\+$/d' "$list_file" > "$new_list_file"
wc -l "$new_list_file"
# or wc -l < "$new_list_file" if you want to prevent it from printing the filename
予期しない結果の例として、ここの文字列に改行が追加されていない場合は、次のコマンドの予想結果を考慮して実行してください。
echo -n "Content" | wc -l
答えは次のとおりです:0