파일을 정렬된 상태로 유지하면서 첫 번째 단어 바꾸기

파일을 정렬된 상태로 유지하면서 첫 번째 단어 바꾸기

입력 파일을 편집하기 위해 쉘 스크립트를 작성하려고 합니다. 입력 파일의 데이터 구조는 다음과 같습니다.

1000␣␣␣␣␣␣␣␣␣␣␣␣: final time
1000            : print time
0.1             : time step

첫 번째 줄에서 강조했듯이 정렬에는 공백을 사용하십시오. 현재 sed대체 매개변수(각 줄의 첫 번째 "단어")를 사용하고 있습니다 .

레이블 정렬을 엉망으로 만들지 않고서는 이 작업을 수행할 수 있는 방법을 찾을 수 없습니다. 나는 어떤 제안이라도 받아들일 것입니다. 특별히 전달하려고 하는 것은 아닙니다 sed. 예를 들어 탭을 사용하여 입력 파일의 구조를 변경할 수 있습니다.

다음은 스크립트에서 수행하려는 작업의 예입니다.

input file
----------
1000␣␣␣␣␣␣␣␣␣␣␣␣: final time
1000            : print time
0.1             : time step
running the script
------------------
$ script --final-time=100
input file after running the script
-----------------------------------
100␣␣␣␣␣␣␣␣␣␣␣␣␣: final time
1000            : print time
0.1             : time step

대체 문자열의 길이는 미리 알 수 없습니다. 고정되지 않으며 최대 6자를 포함할 수 있습니다.

답변1

대신 사용하여 awk필드의 형식을 올바른 너비로 지정 하세요 sprintf(). 이는 를 사용하는 것보다 더 간단할 가능성이 높습니다 sed.

$ cat file
1000            : final time
1000            : print time
0.1             : time step
$ awk -F ':' -v sect=' final time' -v val='100' 'BEGIN { OFS=FS } $2 == sect { $1 = sprintf("%-16s", val) }; 1' file
100             : final time
1000            : print time
0.1             : time step

이것은 분리된 필드로 구성된 입력 라인을 처리합니다 :. 두 번째 필드가 sect명령줄에서 변수에 할당된 문자열에 해당하는 경우 첫 번째 필드는 awk명령줄에서 할당된 값으로 대체됩니다.val

여기에서 사용된 sprintf()형식 문자열은 입니다 %-16s. 에 있는지 확인하세요 :.

동일한 명령을 사용하여 "시간 단계"를 설정하려면 sect합계의 다른 값을 삽입하면 됩니다 val.

$ awk -F ':' -v sect=' time step' -v val='0.12121212' 'BEGIN { OFS=FS } $2 == sect { $1 = sprintf("%-16s", val) }; 1' file
1000            : final time
1000            : print time
0.12121212      : time step

값 시작 부분의 공백은 sect데이터의 공백 이후에 고려되어야 합니다 :. 당신은 또한 이것을 할 수 있습니다

$ awk -F ':' -v sect='time step' -v val='0.12121212' 'BEGIN { OFS=FS } $2 == " " sect { $1 = sprintf("%-16s", val) }; 1' file
1000            : final time
1000            : print time
0.12121212      : time step

sect( 두 번째 열 값에 대한 테스트를 위해 값의 공백을 옮겼습니다 .)


스크립트 제안(입력 파일의 정적 파일 경로를 사용합니다.산출수정된 데이터):

#!/bin/sh

filepath=some/file/path

if [ "$#" -ne 2 ]; then
    echo expecting two arguments >&2
    exit 1
fi

case $1 in
    --final-time) sect='final time' ;;
    --print-time) sect='print time' ;;
    --time-step)  sect='time step'  ;;
    *)
        printf 'Unknown argument: %s\n' "$1" >&2
        exit 1
esac

val=$2

awk -F ':' -v sect="$sect" -v val="$val" '
    BEGIN { OFS=FS }
    $2 == " " sect { $1 = sprintf("%-16s", val) }; 1' "$filepath"

답변2

약간 sed의 마법

v=100; l=${#v}; sed -E "/final/s/[0-9.]/ /g; s/^[ ]{"$l"}/"$v"/" file

우리는 그것을 찾고 있으므로 이를 일치의 전제 조건으로 만든 다음 다음을 final사용하여 모든 숫자와 소수를 제거합니다.[0-9.]

sed -E "/final/s/[0-9.]/ /g;

sed이전 공백을 대체하기 위해 후반부를 작성합니다 {$l}. $v이는 $l단지 길이에 불과 합니다.$v

s/^[ ]{"$l"}/"$v"/"

임무 완료.

관련 정보