目录中的文件如下所示:
A_1_email.txt
A_1_phone.txt
A_2_email.txt
A_2_phone.txt
B_1_email.txt
B_1_phone.txt
B_2_email.txt
B_2_phone.txt我想要的:
合并文件A_1_email.txt和A_1_phone.txt;合并文件B_1_email.txt和B_1_phone.txt等。
我的意思是:如果文件名的第一个到标志匹配(例如,A到A;1到1),则合并文件。
我是如何尝试这样做的:
ls * | cut -d "_" -f 1-2 | sort | uniq -c | awk '{print $2}' > names && for name in
$(cat names); do我在这里迷失了方向,真的不知道该如何继续下去。
发布于 2013-02-13 15:56:05
我将假设所有文件都有制表符分隔的名称-值对,其中值是相应的电子邮件或电话。如果不是这样,请进行一些预排序或适当地修改。
ls *_{email,phone}.txt |
cut -d "_" -f1-2 | # could also do this with variable expansion
sort -u |
awk '{ printf("join %s_email.txt %s_phone.txt\n", $1, $1) }' |
sh这样做的目的是识别文件的唯一前缀,并使用'awk‘生成用于连接这些文件对的shell命令,然后将这些命令通过管道传输到sh以实际运行这些命令。
发布于 2013-02-13 23:43:28
下面是基于@MichaelJ.Barber的回答(它有使用join的绝佳想法),但具体目的是避免使用dangerous practice of parsing the output of ls
# Simple loop: avoids subshells, pipelines
for file in *_email.txt; do
if [[ -r "$file" && -r "${file%_*}_phone.txt" ]]; then
join "$file" "${file%_*}_phone.txt"
fi
done或
##
# Use IFS and a function to avoid contaminating the global environment.
joinEmailPhone() {
local IFS=$'\n'
local -x LC_COLLATE=C # Ensure glob expansion sorting makes sense.
# According to `man (1) bash`, globs expand sorted "alphabetically".
# If we use LC_COLLATE=C, we don't need to sort again.
# Use an awk test (!seen[$0]++) to ensure uniqueness and a parameter expansion instead of cut
awk '!seen[$0]++{ printf("join %s_email.txt %s_phone.txt\n", $1, $1) }' <<< "${*%_*}" | sh
}
joinEmailPhone *但在所有的可能性中(同样假设是LC_COLLATE=C),你都可以逃脱惩罚:
printf 'join %s %s\n' * | sh发布于 2013-02-13 20:56:22
在给定的场景中,您可以使用printf '%s\n' *_{email,phone}.txt | ...而不是ls *-...,即在文件路径名中不需要换行符。至少少了一个外部命令!
https://stackoverflow.com/questions/14848588
复制相似问题