
私は何千もの.xyz
ファイルを持っていますが、すべて同じディレクトリに数値データがあります。その中には、最後に「END」というテキスト文字列があります。grep
元のファイル名の末尾に何かを追加しながら、「END」が削除され、新しいファイルが生成されるようにコマンドを繰り返す方法がわかりません。
私のファイルのいくつかの最後の数行の例
-1.10949170 55.68890280 -67.60000000
-0.92807500 55.64095280 -89.80000000
-0.95770560 55.66495830 -82.40000000
-0.90995000 55.63676110 -94.00000000
-1.03738890 55.65107220 -70.20000000
END
多くのファイルからENDを削除したいです。
-1.10949170 55.68890280 -67.60000000
-0.92807500 55.64095280 -89.80000000
-0.95770560 55.66495830 -82.40000000
-0.90995000 55.63676110 -94.00000000
-1.03738890 55.65107220 -70.20000000
元のファイル名:survey_2015_xxx.xyz
新しいファイル名: survey_2015_xxx_s.xyz
答え1
head
負のオフセットをサポートする場合:
for file in *.xyz; do
if [ "$(tail -n 1 < "$file")" = END ]; then
head -n -1 < "$file" > "${file%.xyz}_s.xyz"
fi
done
(そうでない場合head -n -1
に置き換えてくださいsed '$d'
)。
次の方法で効率を向上させることができますksh93
。
for file in *.xyz; do
if IFS= read -r last4 < "$file" <#((EOF-4)) <#((here=CUR)) &&
[ "$last4" = END ]; then
command /opt/ast/bin/head -c "$here" < "$file" > "${file/%.xyz/_s\0}"
fi
done
組み込みコマンドのみを使用するためです。
ファイルシステムが参照リンクコピーをサポートしている場合(つまり、変更されるまでデータが繰り返されないファイルをコピーして時間とディスク容量を節約する場合)、ksh93
GNUを引き続きcp
使用できます。
for file in *.xyz; do
if IFS= read -r last4 < "$file" <#((EOF-4)) &&
[ "$last4" = END ]; then
newfile=${file/%.xyz/_s\0}
cp --reflink=auto -- "$file" "$newfile" &&
: 1<>; "$newfile" >#((EOF-4))
fi
done
つまり、私たちはreflinkのコピーを作成し、最後に4バイトを切り捨てます。
答え2
もう一つのed
選択肢は一度だけ住んでいるので、次のようになります。
for f in *.xyz; do
printf '%s\n' ';g/END/d\' "w ${f%.xyz}_s.xyz" q | ed -s "$f"
done
ファイル名に関する注意:
- ファイル名はで始まってはいけません
!
。それ以外の場合は、ed
バッファをコマンドにパイプしようとします。 ed
スペース文字はコマンドをパス名引数と区別するために使用されるため、ファイルw
名の先頭のスペースは保持されません。- 改行を含むファイル名は問題を引き起こします。
ed
改行はコマンドを区切るために使用されるためです。
通常の世界では、これらの制限のどれも重要ではありません。よく… …
答え3
ただ別のソリューションを使用してくださいsed
for file in *.xyz
do
if [ "$(sed -e '$!d' $file)" = END ]
then
sed -e '$d' $file > $file_s.xyz
fi
done