使 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
拼接到前面的file3
。 Look 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.new
、file2.new
和 file3.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 删除 解析日期,例如 d1
和 d2
date1 和 date2 在:
stuff_20090413T235945_20090414T235944_end
| d1 | | d2 |
然后你只需从 d1
中减去 1
到 date0 或 d0
中,然后使用 d0
和 d1
构造一个先前的文件名 _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_
)
如果您有任何问题,请告诉我。
我有一个很大的数据文件目录,我正在处理这些文件以使它们成为所需的格式。它们每个都过早开始和结束 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
拼接到前面的file3
。 Look 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.new
、file2.new
和 file3.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 删除 解析日期,例如 d1
和 d2
date1 和 date2 在:
stuff_20090413T235945_20090414T235944_end
| d1 | | d2 |
然后你只需从 d1
中减去 1
到 date0 或 d0
中,然后使用 d0
和 d1
构造一个先前的文件名 _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_
)
如果您有任何问题,请告诉我。