基本的に、ファイルから入力テキストとして取得し、そのファイルから行を削除して、出力を同じファイルに送り返します。それがより明確になった場合、これらの線に沿って何か。
grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name > file_name
ただし、これを行うと、空のファイルになります。何かご意見は?
Bashは最初にリダイレクトを処理してからコマンドを実行するため、これを行うことはできません。そのため、grepはfile_nameを見るまでにすでに空です。ただし、一時ファイルを使用できます。
#!/bin/sh
tmpfile=$(mktemp)
grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name > ${tmpfile}
cat ${tmpfile} > file_name
rm -f ${tmpfile}
そのように、mktemp
を使用してtmpfileを作成することを検討してください。ただし、POSIXではないことに注意してください。
この種のタスクには sponge を使用します。 moreutilsの一部。
このコマンドを試してください:
grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name | sponge file_name
代わりにsedを使用します。
sed -i '/seg[0-9]\{1,\}\.[0-9]\{1\}/d' file_name
このシンプルなものを試してください
grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name | tee file_name
今回はファイルは空白になりません:)、出力も端末に出力されます。
同じファイルにリダイレクト演算子(>
または>>
)を使用することはできません。優先順位が高く、コマンドが呼び出される前にファイルを作成/切り捨てるからです。これを避けるには、tee
、sponge
、sed -i
などの適切なツール、またはファイルに結果を書き込むことができる他のツール(たとえば、sort file -o file
)を使用する必要があります。
基本的に、入力を同じ元のファイルにリダイレクトすることは意味がなく、そのために適切なインプレースエディター、たとえばExエディター(Vimの一部)を使用する必要があります。
ex '+g/seg[0-9]\{1,\}\.[0-9]\{1\}/d' -scwq file_name
ここで:
'+cmd'
/-c
-Ex/Vimコマンドを実行しますg/pattern/d
- global (help :g
)を使用してパターンに一致する行を削除します-s
-サイレントモード(man ex
)-c wq
-:write
および:quit
コマンドを実行しますsed
を使用して同じことを達成できます(他の回答で既に示したように)が、in-place(-i
)は非標準のFreeBSDです拡張(Unix/Linux間で異なる動作をする可能性があります)および基本的にはstreameditor、ファイルエディタではありません。参照: Exモードには実用性はありますか?
ライナーの代替-ファイルの内容を変数として設定します。
VAR=`cat file_name`; echo "$VAR"|grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' > file_name
この質問は検索エンジンのトップの結果であるため、ここに https://serverfault.com/a/547331 からのワンライナーがあります。これはsponge
(多くの場合、 OS Xのようなバニラのインストールの一部ではありません):
echo "$(grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name)" > file_name
または一般的な場合:
echo "$(cat file_name)" > file_name
https://askubuntu.com/a/752451 からのテスト:
printf "hello\nworld\n" > file_uniquely_named.txt && for ((i=0; i<1000; i++)); do echo "$(cat file_uniquely_named.txt)" > file_uniquely_named.txt; done; cat file_uniquely_named.txt; rm file_uniquely_named.txt
印刷する必要があります:
hello
world
一方、cat file_uniquely_named.txt > file_uniquely_named.txt
現在のシェル:
printf "hello\nworld\n" > file_uniquely_named.txt && for ((i=0; i<1000; i++)); do cat file_uniquely_named.txt > file_uniquely_named.txt; done; cat file_uniquely_named.txt; rm file_uniquely_named.txt
空の文字列を出力します。
私はこれを大きなファイル(おそらく2または4 GB以上)でテストしていません。
Hart Simha および kos からこの回答を借りました。
SlurpはPOSIX Awkで使用できます。
!/seg[0-9]\{1,\}\.[0-9]\{1\}/ {
q = q ? q RS $0 : $0
}
END {
print q > ARGV[1]
}
process-substitution を使用してそれを行うことができます。
ただし、bashはすべてのパイプを非同期で開くため、ハックのようなものです。sleep
を使用してYMMVを使用する必要があります。
あなたの例では:
_grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name > >(sleep 1 && cat > file_name)
_
>(sleep 1 && cat > file_name)
は、grepからの出力を受け取る一時ファイルを作成しますsleep 1
_は、入力ファイルを解析するためにgrep時間を与えるために1秒遅れますcat > file_name
_が出力を書き込みますed
もあります(sed -i
の代替として):
# cf. http://wiki.bash-hackers.org/howto/edit-ed
printf '%s\n' H 'g/seg[0-9]\{1,\}\.[0-9]\{1\}/d' wq | ed -s file_name
これを試して
echo -e "AAA\nBBB\nCCC" > testfile
cat testfile
AAA
BBB
CCC
echo "$(grep -v 'AAA' testfile)" > testfile
cat testfile
BBB
CCC
これを行うには、通常teeプログラムを使用します。
grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name | tee file_name
一時ファイルを作成および削除します。
以下は、sponge
を必要とせずに、moreutils
と同じことを実現します。
shuf --output=file --random-source=/dev/zero
--random-source=/dev/zero
partはshuf
をだましてシャッフルを一切行わずにその処理を実行するため、入力を変更せずにバッファリングします。
ただし、パフォーマンス上の理由から、一時ファイルを使用することをお勧めします。それで、一般的な方法であなたのためにそれをする私が書いた関数があります:
# Pipes a file into a command, and pipes the output of that command
# back into the same file, ensuring that the file is not truncated.
# Parameters:
# $1: the file.
# $2: the command. (With $3... being its arguments.)
# See https://stackoverflow.com/a/55655338/773113
function siphon
{
local tmp=$(mktemp)
local file="$1"
shift
$* < "$file" > "$tmp"
mv "$tmp" "$file"
}