我有 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