从文件名中提取字符串并将其插入到文件中

时间:2016-02-23 07:10:54

标签: bash unix awk

我想编写一个bash脚本,用于从文件名中提取字符串,并将该字符串插入同一文件中的特定位置。

例如: 在/root目录下,有不同的日期目录201602012016020220160203,每个目录下都有一个文件abc20160201.databc20160202.dat,{ {1}}。

我的要求是我需要先从每个文件名中提取日期,然后将该日期插入文件中每条记录的第二列。

用于提取我正在使用的日期

abc20160203.dat

并插入我正在使用的日期

f=abc20160201.dat
s=`echo $f | cut -c 4-11`
echo "$f -> $s"

但是在我的awk 'BEGIN { OFS = "~"; ORS = "\n" ; date="20160201" ; IFS = "~"} { $1=date"~"$1 ; print } ' file > tempdate 命令中,日期将出现在第一列中。请告诉我这里我做错了什么。

执行此操作的文件是一个分隔文件,其中的字段以awk个字符分隔。

或者,如果有人有更好的解决方案,请告诉我。

1 个答案:

答案 0 :(得分:0)

输入字段分隔符的变量是FS,而不是IFS。因此,输入行根本不会被拆分,因此当您在字段1之后添加日期时,它将显示在该行的末尾。

你应该可以使用:

f=abc20160201.dat
s=$(echo $f | cut -c 4-11)
awk -v date="$s" 'BEGIN { FS = OFS = "~" } { $1 = $1 OFS date; print }' $f

生成修改后的输出到标准输出。 AFAIK,awk没有覆盖选项,因此如果要“就地”修改文件,则将脚本的输出写入临时文件,然后复制或移动临时文件超过原件(如果你复制,删除临时)。复制保留硬链接和符号链接(以及所有者,组,权限);移动没有。如果文件名既不是符号链接也不是链接文件,则移动更简单。 (复制总是“工作”,但副本需要移动时间长,需要移除,并且窗口较长,而覆盖副本可能会在中断时留下不完整的文件。)

概括一点:

for file in /root/2016????/*.dat
do
    tmp=$(mktemp "$(dirname "$file")/tmp.XXXXXX)")
    awk -v date="$(basename "$file" | cut -c 4-11)" \
        'BEGIN { FS = OFS = "~" } { $1 = $1 OFS date; print }' "$file" >"$tmp"
    mv "$tmp" "$file"
done

首选$(…)优于反引号的原因之一是使用$(…)管理嵌套操作和引用要容易得多。 mktemp命令在与源文件相同的目录中创建临时文件;您可以合法地决定使用mktemp "${TMPDIR:-/tmp}/tmp.XXXXXX代替。一个更通用的脚本将迭代"$@"(它传递的参数),但它可能需要验证文件的基本名称是否符合您需要/期望的格式。

添加代码来处理清理中断或在复制和移动之间进行选择,这仍然是读者的练习。请注意,该脚本不会尝试检测之前是否已在文件上运行。如果你在同一个文件上运行它三次,你最终会得到包含日期的第2-4列。