我有一系列文件,第一行有两个数字(即 170 1742),然后是其他几行。如果我想在每个文件中替换其一半的第一个数字(即 85 1742),我在 Unix 中该怎么做?
答案1
perl -pi -e 's|\d+|$&/2|e if $. == 1; close ARGV if eof' ./*.txt
将用相应数字一半的规范十进制表示形式替换当前目录中每个非隐藏txt
文件第一行的第一个十进制数字序列(例如,006 为 3,007 为 3.5)。
如果数字很大(如大于1e20),perl
可以改用工程表示法(5e+19)。
显然,该方法仅对十进制整数有效。当应用于.1
它时,会给出.5
而不是0.05
;当应用于 1.5 时,它会给出0.5.5
而不是0.75
;当应用于 时0x10
,它会给出0x10
(仅0
减半)而不是 8 或 0x8 等等。
如果您想处理任何表示法的十进制数字(1、010(表示 10,而不是八进制 8)、-1.123、2.23e-4、inf、无穷大、NaN...)),您需要调整匹配正则表达式,例如:
s{(\d*\.\d+|\d+\.?)(e[-+]?\d+)?|nan|inf(inity)?}{$&/2}ie
或者对数字在行中的位置做出一些假设,例如它是否是第一个非空格字符序列:
s{\S+}{$&/2}e
答案2
像这样的东西吗?
awk 'FNR==1{print $1/2,$2;next}1' ./*.txt #or /directory/* or just file.txt
甚至
awk 'FNR==1{$1=$1/2}1' file1
上面的 awk 将在屏幕上打印相应的结果,或者您可以使用以下命令将修改后的输出重定向到新文件>newfile
使用 GNU awk ,您可以使用以下命令直接在原始文件中应用更改gnu awk 就地选项:
awk -i inplace 'FNR==1{$1=$1/2}1' file1
如果你的 awk 不支持 inplace ,你可以像这样手动完成
awk 'FNR==1{$1=$1/2}1' file > newfile && mv newfile file
这实际上就是 awk(甚至 sed)就地编辑在幕后所做的事情。
答案3
tempd=$(mktemp -d)
for f in ./*.csv
do
< "$f" \
sed -e '1y/\t-/ _/; 1!s/.*/[&]/' |
dc -e '
[q]sq
[?z0=q pc z0=?]s? # macro "?" to print line
?r2/ n32anpc l?x # 1st line div/2 the last stack elem print it+spc+2nd
' \
> "$tempd/$f"
mv "$tempd/$f" .
done
rm -r "$tempd"