使 cat 命令在目录中递归循环操作

Make cat command to operate recursively looping through a directory

我有一个很大的数据文件目录,我正在处理这些文件以使它们成为所需的格式。它们每个都过早开始和结束 15 行,这意味着我需要从一个文件中删除前 15 行并将它们粘贴到序列中 previous 文件的末尾。

首先,我编写了以下代码将相关数据分成简单的块:

#!/bin/bash

destination='media/user/directory/'
for file1 in `ls $destination*.ascii`
do
    echo $file1
    file2="${file1}.end"
    file3="${file1}.snip"
    sed -e '16,$d' $file1 > $file2
    sed -e '1,15d' $file1 > $file3
done

这很完美,所以下一步是世界上最简单的 cat 命令:

cat $file3 $file2 > outfile

然而,我需要做的是将file2拼接到前面的file3Look at this screenshot 目录以便更好地理解。

查看这些文件是如何随时间顺序排列的:

*_20090412T235945_20090413T235944_*    ### April 13
*_20090413T235945_20090414T235944_*    ### April 14

所以我需要从上面的 4 月 14 日示例中截取 15 行并将其粘贴到 4 月 13 日示例的末尾。

这不一定是原始代码的一部分,事实上,如果不是,那可能是最好的。我只是希望有人能够帮助我实现这一目标。

提前致谢!如果有任何我不清楚的地方需要进一步解释,请告诉我。

"I need to strip the first 15 lines off one file and paste them to the end of the previous file in the sequence."

如果我理解正确的话,一行代码就可以搞定:

awk 'NR==1 || FNR==16{close(f); f=FILENAME ".new"} {print>f}' file1 file2 file3

当它有 运行 时,文件 file1.newfile2.newfile3.new 将采用新格式并传输行。当然,您不限于三个文件:您可以在命令行中指定任意多个文件。

例子

为了让我们的例子简短,我们只去掉前 2 行而不是 15 行。考虑这些测试文件:

$ cat file1
1
2
3
$ cat file2
4
5
6
7
8
$ cat file3
9
10
11
12
13
14
15

这是运行我们命令的结果:

$ awk 'NR==1 || FNR==3{close(f); f=FILENAME ".new"} {print>f}' file1 file2 file3
$ cat file1.new
1
2
3
4
5
$ cat file2.new
6
7
8
9
10
$ cat file3.new
11
12
13
14
15

如您所见,每个文件的前两行已转移到前面的文件中。

工作原理

awk 逐行隐式读取每个文件。我们代码的工作是根据行号选择一行应该写入哪个新文件。变量 f 将包含我们正在写入的文件的名称。

  • NR==1 || FNR==16{f=FILENAME ".new"}

    当我们读取第一个文件的第一行时,NR==1,或者当我们读取我们所在文件的第 16 行时,FNR==16,我们更新 f 为当前文件的名称,并在末尾添加 .new

    对于传输 2 行而不是 15 行的简短示例,我们使用相同的代码,但将 FNR==16 替换为 FNR==3

  • print>f

    这会将当前行打印到文件 f

    (如果这是 shell 脚本,我们将使用 >>。这不是 shell 脚本。这是 awk。)

使用 glob 指定文件名

destination='media/user/directory/'
awk 'NR==1 || FNR==16{close(f); f=FILENAME ".new"} {print>f}'  "$destination"*.ascii

您可以将之前的 $file3 值存储在一个变量中(并检查它是否不是第一个 运行 -z 检查):

#!/bin/bash

destination='media/user/directory/'
prev=""
for file1 in $destination*.ascii
do
    echo $file1
    file2="${file1}.end"
    file3="${file1}.snip"
    sed -e '16,$d' $file1 > $file2
    sed -e '1,15d' $file1 > $file3
    if [ -z "$prev" ]; then
       cat $prev $file2 > outfile
    fi
    prev=$file3
done

你的任务一点也不难。您想要收集目录中所有 _end 文件的列表(使用 for 循环和 globbing,而不是循环 ls 的结果)。拥有所有 end 文件后,您只需使用 参数扩展 w/substing 删除 解析日期,例如 d1d2 date1 和 date2 在:

stuff_20090413T235945_20090414T235944_end
     |    d1  |      |    d2  |

然后你只需从 d1 中减去 1 到 date0 或 d0 中,然后使用 d0d1 构造一个先前的文件名 _snip 而不是 _end。然后只测试以前的 _snip 文件名是否存在,如果存在,将您的信息从当前 _end 文件粘贴到以前的 _snip 文件。例如

#!/bin/bash

for i in *end; do         ## find all _end files
    d1="${i#*stuff_}"     ## isolate first date in filename
    d1="${d1%%T*}"
    d2="${i%T*}"          ## isolate second date
    d2="${d2##*_}"
    d0=$((d1 - 1))        ## subtract 1 from first, get snip d1
    prev="${i/$d1/$d0}"   ## create previous 'snip' filename
    prev="${prev/$d2/$d1}"
    prev="${prev%end}snip"
    if [ -f "$prev" ]     ## test that prev snip file exists
    then
        printf "paste to : %s\n" "$prev"
        printf "    from : %s\n\n" "$i"
    fi
done

测试输入文件

$ ls -1
stuff_20090413T235945_20090414T235944_end
stuff_20090413T235945_20090414T235944_snip
stuff_20090414T235945_20090415T235944_end
stuff_20090414T235945_20090415T235944_snip
stuff_20090415T235945_20090416T235944_end
stuff_20090415T235945_20090416T235944_snip
stuff_20090416T235945_20090417T235944_end
stuff_20090416T235945_20090417T235944_snip
stuff_20090417T235945_20090418T235944_end
stuff_20090417T235945_20090418T235944_snip
stuff_20090418T235945_20090419T235944_end
stuff_20090418T235945_20090419T235944_snip

例子Use/Output

$ bash endsnip.sh
paste to : stuff_20090413T235945_20090414T235944_snip
    from : stuff_20090414T235945_20090415T235944_end

paste to : stuff_20090414T235945_20090415T235944_snip
    from : stuff_20090415T235945_20090416T235944_end

paste to : stuff_20090415T235945_20090416T235944_snip
    from : stuff_20090416T235945_20090417T235944_end

paste to : stuff_20090416T235945_20090417T235944_snip
    from : stuff_20090417T235945_20090418T235944_end

paste to : stuff_20090417T235945_20090418T235944_snip
    from : stuff_20090418T235945_20090419T235944_end

(当然用你实际的前缀替换stuff_

如果您有任何问题,请告诉我。