我在macOS上有ns_up /目录中的以下文件:
sqRatio_ist_LogSplineInterpPk_iz_260.dat
sqRatio_ist_LogSplineInterpPk_iz_261.dat
sqRatio_ist_LogSplineInterpPk_iz_262.dat
sqRatio_ist_LogSplineInterpPk_iz_263.dat
sqRatio_ist_LogSplineInterpPk_iz_264.dat
sqRatio_ist_LogSplineInterpPk_iz_265.dat
sqRatio_ist_LogSplineInterpPk_iz_266.dat
sqRatio_ist_LogSplineInterpPk_iz_267.dat
sqRatio_ist_LogSplineInterpPk_iz_268.dat
sqRatio_ist_LogSplineInterpPk_iz_269.dat
sqRatio_ist_LogSplineInterpPk_iz_270.dat
sqRatio_ist_LogSplineInterpPk_iz_271.dat
sqRatio_ist_LogSplineInterpPk_iz_272.dat
sqRatio_ist_LogSplineInterpPk_iz_273.dat
sqRatio_ist_LogSplineInterpPk_iz_274.dat
sqRatio_ist_LogSplineInterpPk_iz_275.dat
sqRatio_ist_LogSplineInterpPk_iz_276.dat
sqRatio_ist_LogSplineInterpPk_iz_277.dat
sqRatio_ist_LogSplineInterpPk_iz_278.dat
sqRatio_ist_LogSplineInterpPk_iz_279.dat
sqRatio_ist_LogSplineInterpPk_iz_280.dat
sqRatio_ist_LogSplineInterpPk_iz_281.dat
sqRatio_ist_LogSplineInterpPk_iz_282.dat
sqRatio_ist_LogSplineInterpPk_iz_283.dat
sqRatio_ist_LogSplineInterpPk_iz_284.dat
sqRatio_ist_LogSplineInterpPk_iz_285.dat
sqRatio_ist_LogSplineInterpPk_iz_286.dat
sqRatio_ist_LogSplineInterpPk_iz_287.dat
sqRatio_ist_LogSplineInterpPk_iz_288.dat
sqRatio_ist_LogSplineInterpPk_iz_289.dat
sqRatio_ist_LogSplineInterpPk_iz_290.dat
sqRatio_ist_LogSplineInterpPk_iz_291.dat
sqRatio_ist_LogSplineInterpPk_iz_292.dat
sqRatio_ist_LogSplineInterpPk_iz_293.dat
sqRatio_ist_LogSplineInterpPk_iz_294.dat
sqRatio_ist_LogSplineInterpPk_iz_295.dat
sqRatio_ist_LogSplineInterpPk_iz_296.dat
sqRatio_ist_LogSplineInterpPk_iz_297.dat
sqRatio_ist_LogSplineInterpPk_iz_298.dat
sqRatio_ist_LogSplineInterpPk_iz_299.dat
我想通过减去文件名末尾的值200来重命名每一个,例如:
sqRatio_ist_LogSplineInterpPk_iz_299.dat = sqRatio_ist_LogSplineInterpPk_iz_99.dat
我试过以下的事情:
for i in $(ls ns_up/); do
number=$(echo $i | gsed 's/\(.*\)_\(.*\).dat/\2/')
new_number=$((number-200))
echo $i | gsed 's/_\(.*\)\.dat/"\$new_number"\.dat/'
done
但不幸的是,这不起作用,我不知道为什么。
任何人都有想法?
你可以用homebrew安装(Perl)rename
:
brew install rename
然后尝试:
rename -n 's/(\d+)/$1 - 200/e' ns_up/*dat
-n
说要做一个“干跑”,即说它会做什么,而不是实际做任何事情。
单引号中的Perl表达式在变量$_
中依次接收每个文件名,并且应该修改它并在同一变量中返回新值。
替换说“用这个数字减去200替换它找到的任何相邻数字串。”
e
说要评估替换的右侧。
这种方法有一些额外的好处:
这可能就是你要做的事情(使用bash进行BASH_REMATCH []和$((..))算术运算):
for old in ns_up/*.dat; do
[[ $old =~ ^(.*)_(.*)(\.dat)$ ]] || { printf 'Warning, unexpected old file name format "%s"\n' "$old" >&2; continue; }
new="${BASH_REMATCH[1]}$((${BASH_REMATCH[2]}-200))${BASH_REMATCH[3]}"
[[ -f "$new" ]] && { printf 'Warning, new file name "%s" generated from "%s" already exists, skipping.\n' "$new" "$old" >&2; continue; }
mv -- "$old" "$new"
done
您需要对现有的新测试进行测试,因为新文件名可能与现有文件名相同,您可能不想覆盖它。
这可能对你有用(GNU并行):
parallel --dryrun mv {} '{= s/\d+/& - 200/e =}' ::: *.dat
检查生成的命令后,删除--dryrun
选项。
试过gnu sed:
find . -iregex '.+sqRatio_ist_LogSplineInterpPk_iz_2[0-9]+\.dat' -exec sh -c 'mv {} `echo {}|sed -E "s/(.+_)2([0-9]+\.dat)/\1\2/"`' \;
您的命令的问题是您没有mv
命令,并且您不计算新文件名的左侧部分。这有效:
▶ for i in ns_up/* ; do
n=$(echo "$i" | gsed -E 's/(.*)_([0-9]+).dat/\2/')
new_n=$((n - 200))
left=$(echo "$i" | gsed -E 's/[0-9]+.*//')
mv -i "$i" "$left${new_n}.dat"
done
笔记:
mv -i
以防止意外覆盖文件。-E
来使用sed命令来使用扩展正则表达式,这里允许更清晰的语法。gsed -E 's/(.*)_([0-9]+).dat/\2/'
而不是你的gsed 's/\(.*\)_\(.*\).dat/\2/'
,因为明确地匹配[0-9]+
(数字)更明确,更清楚你匹配哪个下划线。