노력하고있어:
- 항상
0 0 0
파일의 첫 번째 줄에 추가됩니다. 2*pi
또는 아래 형식과 유사한 형식으로 3열 파일의 첫 번째 열을 곱합니다6.2832
. 단, 줄이 숫자로 시작하는 경우에만 해당됩니다. 두 번째와 세 번째 열은 그대로 유지됩니다.*
줄이 숫자로 시작하지 않으면 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
추신. 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 십진수로만 계산을 수행할 수 있으므로 ASCII 십진수에만 일치 하도록 대체 항목 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 "$@"