명령줄을 사용하여 열의 모든 항목에 고정 숫자를 곱합니다. 단, 해당 줄이 주석이 아닌 경우에만 해당됩니다.

명령줄을 사용하여 열의 모든 항목에 고정 숫자를 곱합니다. 단, 해당 줄이 주석이 아닌 경우에만 해당됩니다.

노력하고있어:

  1. 항상 0 0 0파일의 첫 번째 줄에 추가됩니다.
  2. 2*pi또는 아래 형식과 유사한 형식으로 3열 파일의 첫 번째 열을 곱합니다 6.2832. 단, 줄이 숫자로 시작하는 경우에만 해당됩니다. 두 번째와 세 번째 열은 그대로 유지됩니다.
  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

추신. 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.83200062.831853

답변4

제목보다 더 큰 일을 처리하려는 것 같습니다.

이것은 완전한 bash 스크립트입니다. Ed Morton의 훌륭한 답변을 바탕으로 구축되었으며 실제로 개선할 수는 없습니다.

혜택:

  1. TAU매직넘버를 변수( )로 추출
  2. 오류 처리( TODO)
  3. 입력 매개변수와 선택적 출력 매개변수를 사용하면 더 쉽게 실행할 수 있습니다.
  4. 파일이 많으면 진행상황 보고
  5. 간격 문제 방지( NOTEs 참조)
  6. 대화형 및 독립적 실행

결점:

  1. bash아니요sh
  2. 줄이 너무 많습니다(주석이 없어도).
#!/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 "$@"

관련 정보