簡體   English   中英

如何使用 bash 腳本替換文本文件中的特定數字?

[英]How do I replace a specific number in a text file using a bash script?

晚上好 - 我非常堅持看起來應該是一個簡單的 sed 命令。 我有一個格式如下的文本文件 (init.input):

任何幫助,將不勝感激!

        100          50           1
        100          50           1
 2 !The number of additional poutlet condition
45,1,1 762.143895,814.862101,0.999395
46,1,1 762.143895,814.862101,0.999395

之前在 bash 腳本中我定義了變量 cfjlines、var1、var2、var3。 在此示例中,cfjlines 指定該注釋行之后的行數,並且等於該行開頭的整數。
如果例如 var1=123.0, var2=456.0, var3=789.0,
我想要一個 bash 腳本函數來替換該文件最后 (cfjlines) 行的最后三個數字,如下所示:

         100          50           1
         100          50           1
 2 !The number of additional poutlet condition
45,1,1 123.0,456.0,789.0
46,1,1 123.0,456.0,789.0

此示例中顯示的所有數字在以后的文件中都會更改,但位置很重要。 我嘗試將值分配給數組然后讀取失敗:```

# Extract the line containing the integer value from the input file                                                                                                                                                                        
line=$(grep "!The number of additional poutlet condition" init.input)
# Extract the integer value from the line                                                                                                                                                                                                  
cfjlines=$(cut -d' ' -f2 <<< "$line")

declare -a numbers

# Extract the last two lines of the file                                                                                                                                                                                                   
last_lines=$(tail -n $cfjlines init.input)

# Delete last rows of init.input                                                                                                                                                                                                           
head -n -$cfjlines init.input > temp.txt ; mv temp.txt init.input

# Loop through the lines of the last lines                                                                                                                                                                                                 
while read -r line; do
  # Replace spaces with commas in the line                                                                                                                                                                                                 
  modified_line=$(echo "$line" | tr ' ' ',')
  # Append the modified line to the end of the original file                                                                                                                                                                               
  echo "$modified_line" >> init.input
done <<< "$last_lines"

# Set the IFS (internal field separator) to a comma                                                                                                                                                                                        
IFS=','
mapfile -t array < <(tail -n 1 init.input)
# Iterate over the elements in the array                                                                                                                                                                                                   
for element in "${array[@]}"; do
  # Split the element into fields using the IFS                                                                                                                                                                                            
  read -ra fields <<< "$element"
  # Replace the last three fields with var1, var2, and var3                                                                                                                                                                                
  fields[-3]="var1"
  fields[-2]="var2"
  fields[-1]="var3"
  # Join the fields back together using the IFS and print the result                                                                                                                                                                       
  printf "%s\n" "${fields[*]}"
done

```

最后一部分給我一個錯誤,指出字段索引是一個錯誤的數組下標,但我認為那是因為我沒有正確地將最后一行的六個值放入六個數組元素中。

再次感謝您的幫助。 謝謝!

正如許多其他人可能會建議您的那樣,bash 不是進行內容操作的非常有效的工具。 所以在下面,我提供了一個基於的解決方案。

您的問題似乎表明前 3 行是靜態的,因此按原樣傳遞。

您的問題還暗示所有剩余的數據行都將第二個分組修改為相同的 3 個指定值 您可以將這些值作為單獨的值傳遞(根據以下腳本的命令行位置),或者您可以將它們作為單個預格式化的字符串傳遞,如果不依賴於這些行的內容。

如果您需要基於行的值,上下文驅動的,基於每行上的值,那么您需要從為“數據”數組進行拆分的行中刪除注釋前綴,並評估/操作這些值在以下 printf 語句之前生成適當的替代品之前。

#!/bin/sh

if [ $# -eq 3 ]
then
    VAR1=$1
    VAR2=$2
    VAR3=$3
else
    VAR1=123.0
    VAR2=456.0
    VAR3=789.0
fi

echo "\
        100          50           1
        100          50           1
 2 !The number of additional poutlet condition
45,1,1 762.143895,814.862101,0.999395
46,1,1 762.143895,814.862101,0.999395" |
awk -v var1="${VAR1}" -v var2="${VAR2}" -v var3="${VAR3}" '{
    if( NR < 4 ){
        ### do not modify first 3 lines
        print $0 ;
    }else{
        ### split line into 2 groupings
        split( $0, raw ) ;

        ### IF ncessary, split second grouping into distinct array values
        #split( raw[2], data, "," ) ;
        #for( i=1 ; i <= 3 ; i++ ){
        #   printf("\t data[%s] = %s\n", i, data[i] ) | "cat >&2 " ;
        #} ;

        ### pass thru first grouping unmodified
        printf("%s ", raw[1] ) ;

        ### replace 3 values on lines
        printf("%s,%s,%s\n", var1, var2, var3 ) ;
    } ;
}'

這是會話的執行日志:

ericthered@OasisMega1:/WORKS$ script.sh 999 777 333
        100          50           1
        100          50           1
 2 !The number of additional poutlet condition
45,1,1 999,777,333
46,1,1 999,777,333
ericthered@OasisMega1:/WORKS$

或使用您提供的默認值,

ericthered@OasisMega1:/WORKS$ script.sh
        100          50           1
        100          50           1
 2 !The number of additional poutlet condition
45,1,1 123.0,456.0,789.0
46,1,1 123.0,456.0,789.0
ericthered@OasisMega1:/WORKS$

根據您給定的輸入,這就是我要做的。

#!/usr/bin/env bash

start=0
var1=123.0
var2=456.0
var3=789.0
last_fields=3
file=init.input

cfjlines=$(
  grep -Po '(?<=\s)\d+(?=\s!The number of additional poutlet condition)' "$file"
)

while IFS= read -ru3 line; do
  if ((start++ >= cfjlines)); then
    IFS=' ' read -ra fields <<< "${line//,/ }"
    fields[-1]="$var3"
    fields[-2]="$var2"
    fields[-3]="$var1"
    temp=$(IFS=','; printf '%s\n' "${fields[*]:last_fields}")
    temp1="${fields[*]::last_fields}"
    printf '%s\n' "${temp1// /,} $temp"
  else
    printf '%s\n' "$line"
  fi
done 3< "$file"

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM