替换第一个单词保持文件对齐

替换第一个单词保持文件对齐

我正在尝试编写一个 Shell 脚本来编辑输入文件。输入文件中的数据结构如下:

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"/"

任务完成。

相关内容