固定长度文件替换为 sed 或 awk

固定长度文件替换为 sed 或 awk

我有 487 字节的固定长度文件,每个记录位置 407-415(9 字节)是一个数字字段。有时我们会在该字段中收到字母和数字字符的组合(123ABC123,ABC000123....)。如果记录包含这样的内容,我们希望在这些字节中替换为 00000000。

答案1

和 awk 解决方案

awk 'BEGIN{FS=OFS=""}{f=0;for(i=407;i<=415;i++){if($i!~/0-9/){f=1}};if(f){for(i=407;i<=415;i++){$i=0}};print }' fixed

我们定义字段分隔符为空,每个字符都是一个字段。然后我们将每个记录的标志设置f为 0(假设为数字)。我们将字符 407-415 与 /0-9/ 进行比较。如果有任何不匹配,我们将 f 设置为 1。然后,如果 f=1,我们将所有 9 个字符替换为 0 并打印该行。

答案2

由于其他答案对我来说看起来很复杂,这里有一个简单的sed俏皮话:

sed -E '/^.{406}[0-9]{9}/!s/(.{406}).{9}/\1000000000/'

扩展(选项-E)正则表达式^.{406}[0-9]{9}匹配行(我假设一条记录是一行,否则将选项添加-z到您的 GNU ),以 406 个随机字符( )sed开头,后跟九个数字字符,因此 407 到 415 都是数字,因此,对于逆匹配 ( ),前 406 个字符保留(替换中代表第一部分),后面的 9 个字符被零替换。^.{406}!\1()

请注意,当您要求进行文本处理时,这是文本处理而不是字节处理。多字节字符计为一个字符,而不是两个字节

答案3

无论您的输入文件是文本还是二进制文件,这都应该有效:

printf %s "$(head -c 406 test_file | xxd -p)" "000000000000000000" "$(tail -c $((487-415)) test_file | xxd -p)" | tr -d '\n' | fold -32 | xxd -p -r -c 16 > test_file_final

或者这个:

printf %s "$(head -c 406 test_file | xxd -p)" "$(head -c 9 /dev/zero | xxd -p)" "$(tail -c $((487-415)) test_file | xxd -p)" | tr -d '\n' | fold -32 | xxd -p -r -c 16 > test_file_final

您不需要使用:$((487-415))... 您可以简单地使用72... 我这样做是为了更明显地显示数字的来源。

您正在执行的操作是获取文件的前 406 个字节,然后是 9 个空字节(这 9 个空字节可以例如从带有 18 个零的纯字符串生成[第一个选项]或来自的 9 个原始字节/dev/零 [第二个选项])然后从文件的字节 416 开始,直到最后,然后将此树块连接在一起,构建所需的输出。


或者,如果您想替换为零字符(不是空字节),使用这个:

printf %s "$(head -c 406 test_file | xxd -p)" "303030303030303030" "$(tail -c $((487-415)) test_file | xxd -p)" | tr -d '\n' | fold -32 | xxd -p -r -c 16 > test_file_final

无论如何,上面的命令都将替换:不测试任何条件。 如果您想测试这些字节中的十六进制字符,请使用它替换为空字节:

单行版本:

if ! [[ "$(tail -c $((487-406)) test_file | head -c 9)" =~ [[:xdigit:]]{9} ]]; then printf %s "$(head -c 406 test_file | xxd -p)" "000000000000000000" "$(tail -c $((487-415)) test_file | xxd -p)" | tr -d '\n' | fold -32 | xxd -p -r -c 16 > test_file_final; fi

脚本版本:

if ! [[ "$(tail -c $((487-406)) "$1" | head -c 9)" =~ [[:xdigit:]]{9} ]]
then
    printf %s "$(head -c 406 "$1" | xxd -p)" \
              "000000000000000000" \
              "$(tail -c $((487-415)) test_file | xxd -p)" \
              | tr -d '\n' \
              | fold -32 \
              | xxd -p -r -c 16 \
              > "${1}_with_replacement_done"
fi

或者这个,用零字符替换:

单行版本:

if ! [[ "$(tail -c $((487-406)) test_file | head -c 9)" =~ [[:xdigit:]]{9} ]]; then printf %s "$(head -c 406 test_file | xxd -p)" "303030303030303030" "$(tail -c $((487-415)) test_file | xxd -p)" | tr -d '\n' | fold -32 | xxd -p -r -c 16 > test_file_final; fi

脚本版本:

if ! [[ "$(tail -c $((487-406)) "$1" | head -c 9)" =~ [[:xdigit:]]{9} ]]
then
    printf %s "$(head -c 406 "$1" | xxd -p)" \
              "303030303030303030" \
              "$(tail -c $((487-415)) test_file | xxd -p)" \
              | tr -d '\n' \
              | fold -32 \
              | xxd -p -r -c 16 \
              > "${1}_with_replacement_done"
fi

相关内容