2

目录中的文件如下所示:

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.txtA_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

而我在这里迷路了,真的不知道我该如何继续下去。

4

4 回答 4

1

以下内容基于@MichaelJ.Barber 的回答(有一个很好的想法 using join),但其目的是避免解析 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-13T15:43:28.173 回答
0

我假设这些文件都有制表符分隔的名称-值对,其中的值是电子邮件或电话,视情况而定。如果不是这种情况,请进行一些预排序或以其他方式进行适当的修改。

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-13T07:56:05.140 回答
0

您可以在给定的场景中使用printf '%s\n' *_{email,phone}.txt | ...而不是ls *-...,即文件路径名中不会出现换行符。至少少一个外部命令!

于 2013-02-13T12:56:21.653 回答
-1

使用for循环遍历电子邮件文件,使用read具有适当值的命令IFS将文件名拆分为必要的部分。请注意,这确实使用了一项提供的非 POSIX 功能bash,即使用 here-string ( <<<) 将值传递$emailread命令。

for email in *_email.txt; do
    IFS=_ read fst snd <<< $email
    phone=${fst}_${snd}_phone.txt
    # merge $email and $phone
done
于 2013-02-13T13:43:02.407 回答