sedを使用して数値を減らす

sedを使用して数値を減らす

.txtを使用してファイル内のPDFのメタデータを抽出し、各ブックマークの値を整数だけ減らそうとpdftkします。次の行がBookmarkPageNumberあります.txt

BookmarkBegin
BookmarkTitle: Preface
BookmarkLevel: 1
BookmarkPageNumber: 10
BookmarkBegin
BookmarkTitle: Author
... and so on

これを行うには、sedの代替コマンドを使用しようとしています。これが今まで私が持っているものです。

// $1 is the source .txt file; $2 is the decrement
// __ is a placeholder for the variable with the original value
cat $1 | sed "s/BookmarkPageNumber: [0-9]*/BookmarkPageNumber: `expr __ - $2`/" | cat > metadata.txt

__元の値を変数に入れてから、同じsed式でプレースホルダをどのように置き換えることができますか?

答え1

これにはawk算術演算をサポートしているので、使用することをお勧めします。

cat $1 | awk -v d=$2 '/BookmarkPageNumber:/{$2-=d}1'

答え2

awk '!/BookmarkPageNumber:/ {print}; /BookmarkPageNumber:/ {print $1 " " $2-1}' old.txt > new.txt

答え3

別のオプションは、シェル自体を使用することです(たとえば、5を減算したい実際の整数に変更)。

while read key val; do 
    [[ $key == "BookmarkPageNumber:" ]] && let val=val-5;
    echo $key $val; 
done < file 

または、次のツールを使用できますperl

perl -pe 's/(BookmarkPageNumber:\s*)(\d+)$/$1 . ($2-5)/e; ' file 

別のアプローチは次のとおりですawk

awk '$1~/BookmarkPageNumber:/{$2=$2-5}1;' file 

答え4

注:私は彼が最初に読んだ任意の整数でBookmarkPageNumberを減らしたいと思いました。一方、以下の解決策は1万減りました。しかし、努力した結果、完全に除去することは困難です。

--------解決策の一部のみ---------

sedだけを使用したい場合は、次の1行をご覧ください。 sed -r '/^BookmarkPageNumber: /{s/([0-9]*)$/\1@/;:loop {s/0@/@9/;/0@/b loop;};s/1@/_0/;s/2@/_1/;s/3@/_2/;s/4@/_3/;s/5@/_4/;s/6@/_5/;s/7@/_6/;s/8@/_7/;s/9@/_8/;s/ @9+$/ UNDERFLOW/;s/ _0*/ /;s/_//}' $1 >metadata.txt

注:これは自然の10進数でのみ機能します。これが大丈夫です。

ああ、さらにアンダーフロー検出機能もあります。したがって、ページ番号を0に飽和させるには、次のようUNDERFLOWに置き換えます。0

私はこれが知的妄想にすぎないと言う人の意見に同意します。それはまさにそれだからです。

ps:入出力ファイル記述子が同じファイルを指していることを確認する必要があります。そうしないと、ユーザーに書き込み権限があるとファイルが切り捨てられます。

関連情報