shell - 执行 sed 命令时,文件中的某些选项卡会转换为单个空格
问题描述
背景
我有一个 .xyz 文件,我需要从中删除一组特定的行。以及做一些文本替换。我有一个单独的 .txt 文件,其中包含一个整数列表,对应于需要删除的行号,另一个用于需要替换的行。该文件将被调用atomremove.txt
并如下所示。另一个文件的结构类似。
就像一个抢先式 TL;DR:我的输入文件中的选项卡碰巧有一个额外的空格(因为不管有没有一个额外的空格,它们都会对齐到某个位置),最终被转换为输出文件中的单个空格。
14
13
11
10
4
我需要从中删除行的 xyz 文件看起来像这样。
24
Comment block
H 18.38385 15.26701 2.28399
C 19.32295 15.80772 2.28641
O 16.69023 17.37471 2.23138
B 17.99018 17.98940 2.24243
C 22.72612 1.13322 2.17619
C 14.47116 18.37823 2.18809
C 15.85803 18.42398 2.20614
C 20.51484 15.08859 2.30584
C 22.77653 3.65203 2.19000
H 20.41328 14.02079 2.31959
H 22.06640 8.65013 2.27145
C 19.33725 17.20040 2.26894
H 13.96336 17.42048 2.19342
H 21.69450 3.68090 2.22196
C 23.01832 9.16815 2.25575
C 23.48143 2.42830 2.16161
H 22.07113 11.03567 2.32659
C 13.75496 19.59644 2.16380
O 23.01248 6.08053 2.20226
C 12.41476 19.56937 2.14732
C 16.54400 19.61620 2.20021
C 23.50500 4.83405 2.17735
C 23.03249 10.56089 2.28599
O 17.87129 19.42333 2.22107
我的代码
尽管输出不如预期,但我成功地进行了线路移除和替换。它似乎用空格替换了一些选项卡,特别是对于只有 5 个小数的“y”坐标的行。我将首先分享结果输出,然后是我的代码。
这是输出
19
Comment Block
H 18.38385 15.26701 2.28399
C 19.32295 15.80772 2.28641
O 16.69023 17.37471 2.23138
H 22.72612 1.13322 2.17619
C 14.47116 18.37823 2.18809
C 15.85803 18.42398 2.20614
C 20.51484 15.08859 2.30584
C 22.77653 3.65203 2.19000
C 19.33725 17.20040 2.26894
C 23.01832 9.16815 2.25575
C 23.48143 2.42830 2.16161
H 22.07113 11.03567 2.32659
C 13.75496 19.59644 2.16380
O 23.01248 6.08053 2.20226
C 12.41476 19.56937 2.14732
C 16.54400 19.61620 2.20021
C 23.50500 4.83405 2.17735
H 23.03249 10.56089 2.28599
O 17.87129 19.42333 2.22107
这是我的代码。
atomstorefile="./extract_internal/atomremove.txt"
atomchangefile="./extract_internal/atomchange.txt"
temp="temp.txt"
tempp="tempp.txt"
temppp="temppp.txt"
filestoreloc="./"$basefilename"_xyzoutputs/chops"
#get number of files in directory and set a loop for that # of files
numfiles=$( ls "./"$basefilename"_xyzoutputs/splits" | wc -l )
numfiles=$(( numfiles/2 ))
counter=1
while [ $counter -lt $(( numfiles + 1 )) ];
do
#set a loop for each split half
splithalf=1
while [ $splithalf -lt 3 ];
do
#storing the xyz file in a temp file for edits (non destructive)
cat ./"$basefilename"_xyzoutputs/splits/split"$splithalf"-geometry$counter.xyz > $temp
#changin specified atoms
while read line;
do
line=$(( line + 2 ))
sed -i "${line}s/C/H/" $temp
done < $atomchangefile
# removing specified atoms
while read line;
do
line=$(( line + 2 ))
sed -i "${line}d" $temp
done < $atomstorefile
remainatoms=$( wc -l $temp | awk '{print $1}' )
remainatoms=$(( remainatoms - 2 ))
tail -n $remainatoms $temp > $tempp
echo $remainatoms > "$filestoreloc"/split"$splithalf"-geometry$counter.xyz
echo Comment Block >> "$filestoreloc"/split"$splithalf"-geometry$counter.xyz
cat $tempp >> "$filestoreloc"/split"$splithalf"-geometry$counter.xyz
splithalf=$(( splithalf + 1 ))
done
counter=$(( counter + 1 ))
done
我确信解决方案很简单。任何有关导致此问题的原因的见解将不胜感激。
解决方案
你破坏你的空格的原因是你需要引用你的字符串。但是一个更好的解决方案是将所有这些极其复杂的 shell 脚本重构为一个简单的sed
或 Awk 脚本。
假设行号都表示原始输入文件中的行号,试试这个。
tmp=$(mktemp -t atomtmpXXXXXXXXX) || exit
trap 'rm -f "$tmp"' ERR EXIT
( sed 's%$%s/C/H/%' extract_internal/atomchange.txt
sed 's%$%d%' extract_internal/atomremove.txt ) >"$tmp"
ls -l "$tmp"; nl "$tmp" # debugging
for file in "$basefilename"_xyzoutputs/splits/*; do
dst= "$basefilename"_xyzoutputs/chops/${file#*/splits/}
sed -f "$tmp" "$file" >"$dst"
done
这将两个输入文件组合成一个新sed
脚本(值得注意的是,通过sed
);调试行可让您检查结果(一旦您了解其工作原理,可能会删除它)。
您的问题并没有真正解释输入文件与输出文件的关系,所以我不得不猜测一下。重要的更改之一是避免sed -i
在不修改现有文件时;但最重要的是,绝对避免使用sed -i
.
推荐阅读
- c++ - 对对象图进行排序 C++
- stm32 - STM32F411 DWT CYCCNT 计数器宽度
- ios - 使用 Decodable + Realm Swift 解码自定义 JSON
- android - 在 pageData 中使用变量作为数组名
- php - 在子模块中拆分 CSS 并使用 PHP 或预编译器聚合它们
- reactjs - Is Flow replace PropTypes?
- javascript - 防止 Voice Over 读取文本输入中的只读属性
- python - 如何在 maya python ls 命令中选择顶点?
- android - 即使指定了 android:screenOrientation="portrait",Android 也以横向方式启动活动(来自库项目)
- ruby-on-rails - 在多个每个循环内/以上向哈希添加值