努力しています:
- 常に
0 0 0
ファイルの最初の行に追加されます。 2*pi
または、次の形式に似た形式で3列ファイルの最初の列を掛けます6.2832
。ただし、行が数字で始まる場合にのみ適用されます。 2番目と3番目の列はそのまま残ります。*
行が数字で始まらない場合、aはすでにaではない限り、行の先頭に追加されます*
。つまり、すでにコメントされていない限り、現在の行をコメントアウトするだけです。
以下はサンプル入力ファイルです。
* radius, section, index
1.12 A 0
2.0 A 1
* There is white space before this comment
* This is a comment indicating a new section
5 B 0
3.17 B 1
7.3 B 7
This row starts with an alphabet char and should be commented out by the script.
0 C 1
1 C 2
予想される結果は次のとおりです。
0 0 0
* radius, section, index
7.037184 A 0
12.5664 A 1
* There is white space before this comment
* This is a comment indicating a new section
31.416 B 0
19.917744 B 1
45.86736 B 7
* This row starts with an alphabet char and should be commented out by the script.
0 C 1
6.2832 C 2
これまで私がしたこと:
for tempfile in *.txt; do
echo '0 0 0' > temp
cat $tempfile >> temp
awk '{$1*=6.2832}{print}' temp > $tempfile
#awk '/^(0-9)/{$1*=6.2832}{print}' temp > $tempfile
rm temp
done
しかし、上記の例のユースケースでは、このスクリプトは何を行いますか?
0 0 0
0 radius, section, index
7.03718 A 0
12.5664 A 1
0 There is white space before this comment
0 This is a comment indicating a new section
31.416 B 0
19.9177 B 1
45.8674 B 7
0 row starts with an alphabet char and should be commented out by the script.
0 C 1
6.2832 C 2
PS。 Linuxボックスはスタンドアロンで、mlr
ルート/管理者の資格情報もありません。
コミュニティのどんな助けにも感謝します。よろしくお願いします。
氏
答え1
POSIX awkを使用してください。
$ cat tst.awk
NR == 1 {
CONVFMT = "%.17g"
pi = atan2(0, -1)
two_pi = 2 * pi
print 0, 0, 0
}
{
if ( $1 ~ /^[0-9]/ ) {
$1 *= two_pi
}
else {
sub(/^[[:space:]]*\*?[[:space:]]*/,"* ")
}
print
}
$ awk -f tst.awk file
0 0 0
* radius, section, index
7.03718 A 0
12.5664 A 1
* There is white space before this comment
* This is a comment indicating a new section
31.416 B 0
19.9177 B 1
45.8674 B 7
* This row starts with an alphabet char and should be ignored by the script.
0 C 1
6.2832 C 2
答え2
たぶんawkを使ってすべてのことをすることができます。
awk '
( FNR==1 ) { print "0 0 0" } # add a first line containing "0 0 0"
/^[0-9]/ { $1 *= 6.2832 }
/^[a-zA-Z]/ { $0="* " $0 } # comment lines that start with a letter
1 # always true, and no {action} speficied:
# does the default "print $0" action and thus prints every line
' your_input_file > output_file
答え3
そしてperl
:
perl -MMath::Trig -pe '
BEGIN{print "0 0 0\n"; $x = 2 * pi}
unless (s{^\d[\d.]*}{$& * $x}e || /^\s*\*/) {
$_ = "* $_";
}' your-file
ここで、プレフィックスは"* "
数字で始まらず、白いs
速度も数字で始まらない*
。
"* "
aで始まる行だけをプレフィックスとして使用してください。手紙する:
perl -C -MMath::Trig -pe '
BEGIN{print "0 0 0\n"; $x = 2 * pi}
if (/^\pL/) {
$_ = "* $_";
} else {
s{^\d[\d.]*}{$& * $x}ae;
}' your-file
(ここにオプションを追加し、-C
ファイルがUTF-8でエンコードされ、ロケールがその文字エンコーディングを使用していると仮定します)ASCIIに限定されません。アルファベット;ただし、Perlは他のスクリプトの計算ではなくASCII 10進数でのみ計算を実行できるため、ASCII 10進数にのみ一致するように代替項目a
にフラグを追加します。s{...}{...}ae
\d
Math::Trig
モジュールがない場合(定数)、要因定義は次のようにpi
変更できます。$x
$x = 2 * atan2(0, -1)
またはハードコードしてください:
$x = 6.28318530717958647692
計算を実行するときは、できるだけ高い精度(そして有用性)を使用し、最終結果から数字だけを切り捨てる必要があります。そうしないと、乗算後にエラーが拡大する可能性があります。
たとえば、これらの円周をミクロン単位まで正確に表示するには(数値がメートル単位で表示されると仮定)、次のようにします。
perl -MMath::Trig -pe '
BEGIN{print "0 0 0\n"; $x = 2 * pi}
unless (s{^\d[\d.]*}{sprintf "%.6f", $& * $x}e || /^\s*\*/) {
$_ = "* $_";
}' your-file
半径10000000メートルの円の場合、係数に基づいて実際の円周を6.2832
得ることができます。62.832000
62.831853
答え4
タイトルよりも大きなことを処理したいようです。
これは完全なbashスクリプトです。 Ed Mortonの素晴らしい答えに基づいて構築されており、実際には改善することはできません。
特典:
TAU
マジックナンバーを変数()で抽出- エラー処理(
TODO
) - 入力パラメータとオプションの出力パラメータを使用すると、簡単に実行できます。
- ファイルが多い場合は進行状況を報告
- 間隔問題の防止(
NOTE
sを参照) - 対話型および独立実行
欠点:
bash
いいえsh
- 行が多すぎます(コメントがなくても)。
#!/bin/bash
# TODO: Update me for more accuracy
#
TAU=6.2832
# TODO: handle errors
#
trap on_err ERR
on_err() { echo "failed!" >&2; exit 1; }
# awk processing for input files
#
# For every line starting with a number,
# multiply the first number by tau (pi * 2)
#
# For every line not starting with a number,
# change the line to start with a *
#
# Finally, print the line with our changes
#
AWK_PROG="{
if (\$1 ~ /^[[:space:]]*[0-9]/) {
\$1 *= $TAU
} else {
sub(/^[[:space:]]*\\*?[[:space:]]*/, \"* \")
}
print
}"
# Process all files in a directory
#
# Simple usage (reads input from /my/input/*.txt)
#
# process_all_files /my/input
#
# Advanced usage (writes output to /my/output/*.txt)
#
# process_all_files /my/input /my/output
#
process_all_files() {
# Arguments
#
# First argument is the input directory
#
# Second argument (optional) is the output directory
# (a tempfile by default)
#
local in_dir="$1"
local out_dir="${2:-$(mktemp -d)}"
# List all the files in the input directory (save list in tempfile)
#
# NOTE: xargs details
# https://unix.stackexchange.com/questions/175844/use-basename-in-find-exec
#
local file_list="$(mktemp)"
find "$in_dir" -iname '*.txt' -print0 \
| xargs -0 -n1 -- basename \
> "$file_list"
# Log state
#
# Total number of files
local n=$(awk 'END{print NR}' "$file_list")
# Current file number
i=0
# Define log function to print to stderr
#
# NOTE: change log formatting here
#
log() { echo " $i/$n :: $*" >&2; }
# Log the input directory (and number of files to process)
log "$in_dir/*.txt"
# Iterate over the list of files
#
# NOTE: using while read avoids word splitting issues
# https://www.shellcheck.net/wiki/SC2044
#
cat "$file_list" | while read -r file; do
# Update current file number and log the file
((i++))
log "$file"
# Do the actual processing
#
# 1. Write the first line of the file
# 2. Process the rest of the file with awk
#
# Whitespace alignment for clarity:
# First line truncates the output file if it already exists
# Second line appends to the file
#
echo 0 0 0 > "$out_dir/$file"
awk "$AWK_PROG" "$1" >> "$out_dir/$file"
done
}
# Only run the main function if this script was executed directly
#
# If this script is sourced by another script or an interactive session,
# the function will not run until called directly
#
# If this script is loaded over the network,
# it will not execute until it reaches the last line
# It won't execute if it fails halfway through, for example.
#
[[ "$0" == "${BASH_SOURCE[0]}" ]] && process_all_files "$@"