我想编写一个bash脚本,用于从文件名中提取字符串,并将该字符串插入同一文件中的特定位置。
例如:
在/root
目录下,有不同的日期目录20160201
,20160202
,20160203
,每个目录下都有一个文件abc20160201.dat
,abc20160202.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
个字符分隔。
或者,如果有人有更好的解决方案,请告诉我。
答案 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列。