需要迭代子目录,连接文件,用迭代号

需要迭代子目录,连接文件,用迭代号

我正在尝试将三个不同子目录中的文件连接到一个文件中。每个子目录中的文件名完全相同。我想使用循环来迭代子目录,然后将迭代编号放入新目录中新命名的串联文件中。例如目录结构如下:

Foo
|||
||Bar3
|Bar2
Bar1

每个 Bar(?) 文件夹内都有名为:File1、File2、File3 的文件

我想将具有相同名称的文件连接到一个更大的文件,并使用包含数字的新名称:

cat Foo/Bar1/File1 Foo/Bar2/File1 Foo/Bar3/File1 > /combined_files/all_file1

cat Foo/Bar1/File2 Foo/Bar2/File2 Foo/Bar3/File2 > /combined_files/all_file2

cat Foo/Bar1/File3 Foo/Bar2/File3 Foo/Bar3/File3 > /combined_files/all_file3

Foo我可以使用的目录:

for number in {1..3}
    do
    cat Bar1/File$number\_* Bar2/File$number\_* Bar3/File$number\_* > combined_files/'all_files'$number
    done
exit

但我需要一个更通用的脚本,用于更多数量的 Bar 目录和文件。我想要类似的东西

files=`ls ./Run1/ | wc -l`   #to count the number of files and assign a number
For n in {1..$files}
    do
    cat Bar1/File$n\_* Bar2/File$n\_* Bar3/File$n\_* > combined_files/'all_files'$n
    done

但我被困住了。

答案1

#!/bin/sh

for pathname in Foo/Bar1/File*; do
    filename=${pathname##*/}
    cat "$pathname" \
        "Foo/Bar2/$filename" \
        "Foo/Bar3/$filename" >"combined/all_$filename"
done

这将循环遍历名称匹配的所有文件File*Foo/Bar1我们假设该模式与我们实际感兴趣的名称完全匹配)。

对于每个这样的文件,我们提取路径名的文件名部分,产生$filename(这也可以使用 完成filename=$(basename "$pathname"))。然后,我们将原始文件与Foo/Bar2和目录中的相应文件连接起来Foo/Bar3,将结果写入all_$filename其他目录中的新文件。


经过一些错误检查:

#!/bin/sh

for pathname in Foo/Bar1/File*; do
    if [ ! -f "$pathname" ]; then
        printf '% is not a regular file, skipping\n' "$pathname" >&2
        continue
    fi

    filename=${pathname##*/}

    if [ -f "Foo/Bar2/$filename" ] &&
       [ -f "Foo/Bar3/$filename" ]
    then
        cat "$pathname" \
            "Foo/Bar2/$filename" \
            "Foo/Bar3/$filename" >"combined/all_$filename"
    else
        printf 'Missing %s or %s\n' "Foo/Bar2/$filename" "Foo/Bar3/$filename" >&2
    fi
done

还允许有不同数量的BarN子目录的变体。这是假定每个BarN目录都按从 1 到某个大数字的顺序编号。

#!/bin/sh

# This is just used to count the number of BarN subdirectories.
# The number of these will be $#.
set -- Foo/Bar*/

for pathname in Foo/Bar1/File*; do
    filename=${pathname##*/}

    n=1
    while [ "$n" -le "$#" ]; do
        if [ ! -f "Foo/Bar$n/$filename" ]; then
            printf '%s missing, %s will be incomplete\n' \
                "Foo/Bar$n/$filename" "combined/all_$filename" >&2
            break
        fi

        cat "Foo/Bar$n/$filename"
        n=$(( n + 1 ))
    done >"combined/all_$filename"
done

答案2

再次感谢@Kusalananda 和@Debian_yadav。我能够让你的脚本在我的系统上运行。我的实际目录名称现在是:

Joes ||| ||Run3 |Run2 Run1

在每个 RunX 目录中,我创建了名称相同但内容不同的文件

运行1\文件1
运行2\文件1
运行3\文件1

首先,我运行了您展示的简单脚本,并对我的目录结构进行了稍微修改:

回答

#!/bin/bash
for pathname in Run1/File*; do
    filename=${pathname##*/}
    cat "$pathname" \
        "Run2/$filename" \
        "Run3/$filename" > "RunCat/all_$filename"
one

脚本输出是一个文件“allFile1”,其内容为: 123

您的较长(最终)脚本(我命名为 K2script.sh)也适用于我的系统。
稍微修改目录结构后,输出再次完全相同:

回答

#!/bin/sh
# This is just used to count the number of RunN subdirectories.
# The number of these will be $#.
set -- Joes/Run*/

for pathname in Run1/File*; do
    filename=${pathname##*/}

    n=1
    while [ "$n" -le "$#" ]; do
        if [ ! -f "Run$n/$filename" ]; then
            printf '%s missing, %s will be incomplete\n' \
                "Run$n/$filename" "RunCat/all_$filename" >&2
            break
        fi

        cat "Run$n/$filename"
        n=$(( n + 1 ))
    done >"RunCat/all_$filename"
done 

另外,使用来自
另一个 stackexchange 讨论

回答
更改文件夹名称使其可以在我的系统上运行。

#!/bin/bash
for FILE in Run1/* ; do
    FILE2=Run2/${FILE#*/}
    FILE3=Run3/${FILE#*/}
    if [ -f $FILE2 ] ; then
        cat $FILE $FILE2 $FILE3 > RunCat/${FILE#*/}
    fi
done

我已经了解了很多关于while [ "$n" -le "$#" ]; do其工作原理的知识${pathname##*/},但无法完全理解为什么${FILE#*/}其他通配符或正则表达式不起作用时却能起作用。

相关内容