我有一些 Perl 文件,我必须通过一个简单的sed
调用来修改它们。基本上,我必须删除所有这些的第一行。目前,我设法做到了这一点:
find <PATH> -type f -name "*.pl" -exec sed -i '1d' {} \;
然而,我在脚本中使用了这一行,我希望它更......健谈。因此,我决定回显一个计数器(实时),这将显示到目前为止已处理的文件数量。
我知道 Perl 文件的数量可以通过以下方式检索
PERL_FILE_COUNT=$(find <PATH> -name "*.pl" | wc -l)
目前,我有这个
remove_first_line()
{
count=0
echo -ne "Removing first line of Perl files ..."
find <PATH> -type f -name "*.pl" -exec sed -i '1d' {} \; >/dev/null 2>&1
if [ $? -eq 0 ]
then echo "OK"
then echo "FAILED"
fi
}
现在,我想要的输出是这样的:
"Removing first line of Perl files ... 1/209209"
并且该值应该自动更新。但我不知道如何count
使用 find/exec 语句来增加变量。基本上,每次sed
完成文件的工作时,它都应该增加count
变量。
答案1
如果您有 bash 4,请考虑使用 globstar。它为您提供递归通配符。
shopt -s globstar
perlz=( **/*.pl ) # */ Hack to fix syntax highlighting
totes="${#perlz[@]}"
i=0
for file in "${perlz[@]}"; do
printf 'Removing first line of Perl files … %d/%d\r' $((++i)) $totes
ed -s "$file" <<< $'1d\nw' # You can use `sed` if you want to, but ed is an actual file editor
done
echo # print a final newline
该解决方案将适用于名称中包含疯狂字符的文件,并避免使用子 shell。
但如果 bash 4 不是一个选项,您可以使用以下命令重新创建此解决方案find -exec +
:
find . -name '*.pl' -exec bash -c 'totes=$#
i=0
for file; do
printf "Removing first line of Perl files … %d/%d\r" $((++i)) $totes
ed -s "$file" <<< $'\''1d\nw'\'' # Avoid these leaning toothpicks by putting this
# script in a file.
done
echo # print a final newline
' bash {} +
但是,这取决于系统的 ARG_MAX(与上面不同),因此如果文件数量非常大,您仍然可能最终对文件的子集进行多次运行。
答案2
这个怎么样?
#!/bin/bash
failed=0
find . -type f -name "*.pl" | while read file; do
if [ -e "$file" ] && [ -r "$file" ]; then
sed -i~ "1d" "$file"
if [ $? != 0 ]; then
echo "sed returns $? on ($file)"
(( failed++ ))
fi
else
echo "warning ($file) not exists, or not readable"
(( failed++ ))
fi
done
echo "failed execution: $failed"
在这里使用比较安全sed -i~
。 Sed 将旧文件另存为file~
.
答案3
GNUly:
find . -type f -name '*.pl' -size +0c -print0 > list &&
count=$(grep -cz . < list) &&
stdbuf -oL xargs < list -r0 sed -i -e '1{w /dev/stdout' -e 'd;}' |
awk -v c="$count" '{printf "processed file %d/%d\r", NR, c}
END{print ""}'