我正在尝试将三个不同子目录中的文件连接到一个文件中。每个子目录中的文件名完全相同。我想使用循环来迭代子目录,然后将迭代编号放入新目录中新命名的串联文件中。例如目录结构如下:
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#*/}
其他通配符或正则表达式不起作用时却能起作用。