我的硬盘中有5000个文件,名称为ip_file_1,ip_file_2,.... 我有一个只能合并2个文件的可执行文件。如何编写一个脚本,该脚本将所有文件驻留在硬盘中(以ip_file_ *开头)并调用该函数合并所有文件。
我有5000个文件,它们是包含日志记录信息的二进制文件(每个函数调用所花费的时间)。我有另一个可执行文件,它只接受两个文件并根据时间戳合并并给出合并的输出。
我使用以下格式执行
./trace ip_file1 ip_file2 mergefile # I'm not using the trace tool. It's an example
我可以使用可执行文件仅合并两个文件。我想将其自动化以合并所有其他文件。
合并必须按顺序完成(根据时间戳合并)。合并的逻辑已经存在。并且合并的输出将发送到文件。
我的问题不在于如何合并文件。我的问题是如何自动化和合并所有文件而不是两个文件。
答案 0 :(得分:1)
为了避免过多的参数或命令行的参数长度,您希望编写merge
命令,以便它可以采用先前合并的输出并合并另一个文件。原始问题陈述中merge
的描述很少,所以我假设您可以这样做:
merge -o output_file input_file
output_file
可以是先前合并的文件或新文件。如果你能做到这一点,那么将所有这些合并起来很简单:
find drive_path -name "ip_file_*" -exec merge -o output_file {} \;
此处的顺序是文件系统中的目录顺序。如果需要不同的订单,则需要指定。
<强>附录强>
如果您需要按时间戳顺序排列的文件,那么我将修改此方法并创建一个merge
命令,该命令接受一个文本文件作为输入,该文件列出了要合并的所有文件。使用此帖子中提供的信息创建此文件列表:https://superuser.com/questions/294161/unix-linux-find-and-sort-by-date-modified
答案 1 :(得分:1)
如果您的外部合并工具是real_merge
,并且此工具将两个命令行参数的合并输出写入stdout,则以下递归shell函数将执行此任务:
merge_files() {
next=$1; shift
case $# in
0) cat "$next" ;;
1) real_merge "$next" "$1"
*) real_merge "$next" <(merge_files "$@")
esac
}
这种方法是高度并行化的 - 这意味着它将使用尽可能多的CPU和磁盘IO。根据您的可用资源以及您的操作系统管理这些资源的工具,这可能是也可能不是一件好事。
另一种方法是使用临时文件:
swap() {
local var_curr=$1
local var_next=$2
local tmp
tmp="${!var_curr}"
printf -v "$var_curr" "${!var_next}"
printf -v "$var_next" "$tmp"
}
merge_files() {
local tempfile_curr=tempfile_A
local tempfile_next=tempfile_B
local tempfile_A="$(mktemp -t sort-wip-A.XXXXXX)"
local tempfile_B="$(mktemp -t sort-wip-B.XXXXXX)"
while (( $# )); do
if [[ -s ${!tempfile_curr} ]]; then
# we already populated our temporary file
real_merge "${!tempfile_curr}" "$1" "${!tempfile_next}"
swap tempfile_curr tempfile_next
elif (( $# >= 2 )); then
# only two arguments at all
real_merge "$1" "$2" "${!tempfile_curr}"
shift
else
# only one argument at all
cat "$1"
rm -f "$tempfile_A" "$tempfile_B"
return
fi
shift
done
# write output to stdout
cat "${!tempfile_curr}"
# ...and clean up.
rm -f "$tempfile_A" "$tempfile_B"
}
如果文件名的词法排序顺序准确,您可以将其调用为:merge_files ip_file_*
。 (如果他们的名字是零填充的,即。ip_file_00001
,则会出现这种情况,但如果没有填充,则为真。)如果没有,您需要先对名称流进行排序。如果您正在使用bash并且可以使用GNU统计和排序,则可以这样做:
declare -a filenames=()
while IFS='' read -r -d ' ' timestamp && IFS='' read -r -d '' filename; do
filenames+=( "$filename" )
done < <(stat --printf '%Y %n\0' ip_file_* | sort -n -z)
merge_files "${filenames[@]}"