我在多个目录中有一堆文件,每个文件的第一行的日期不正确。我正在尝试编写一个涉及 sed 和 for 循环的脚本。
每个文件都位于其自己的由正确日期组成的目录中。例如,文件可能位于:./2014/06/02/record1,我想将第一行的日期替换为“2014/06/02”。
有许多文件,每个文件都有自己的目录。如何使用 sed 和 for 循环来实现此目的?
答案1
要循环所有文件,假设您位于eg的父目录中2014
并且文件本身被称为record<something>
:
for pathname in 20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*
do
if [ -f "$pathname" ]; then
# ...
fi
done
该模式20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*
将匹配您提到的所有路径名,假设您只有 2000 年到最多 2099 年的顶级目录。
循环中的测试是为了确保该$pathname
值是现有常规文件的路径名(或指向该文件的符号链接)。如果模式不匹配任何内容,则默认情况下(在大多数 shell 中)它将保持不展开状态。测试会发现这一点。
$pathname
要获取上面循环中的目录路径:
dirpath=$( dirname "$pathname" )
或者
dirpath=${pathname%/*}
该dirname
实用程序返回一个字符串,它是给定路径名的目录路径。此变量替换变体删除了最后一个/
中的任何内容$pathname
。在这种情况下,任一命令都会生成相同的结果,但 usingdirname
通常更安全(它会返回a
给定的 string a/b/
,而不是a/b
变量替换会返回的结果)。
要将文件 at 的第一行替换$pathname
为字符串 in $dirpath
(使用 GNUsed
和就地编辑):
sed -i -e '1c\' -e "$dirpath" "$pathname"
c
in 命令将sed
完全删除一行内容并在其位置插入其他内容。在这里,我们仅将其应用于第一行并插入生成的字符串$dirname
,这将是路径名中的日期。
将其合并到脚本中:
#!/bin/sh
for pathname in 20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*
do
if [ -f "$pathname" ]; then
dirpath=${pathname%/*}
sed -i -e '1c\' -e "$dirpath" "$pathname"
fi
done
在文件的备份副本上进行测试。
使用替代的等效实现find
(大部分等效,它不会处理record*
作为常规文件的符号链接的文件):
find 20[0-9][0-9]/ -type f \
-path '20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*' -exec sh -c '
for pathname do
sed -i -e "1c\\" -e "$( dirname "$pathname" )" "$pathname"
done' sh {} +
这采用与解决方案的第一个变体基本相同的循环。
答案2
试试这个脚本:
#!/bin/bash
for YEAR in $(ls -1)
do
echo -n Processing year $YEAR " "
for MONTH in $(ls -1 $YEAR)
do
echo -n month $MONTH " "
for DAY in $(ls -1 $YEAR/$MONTH)
do
echo -n day $DAY
sed -i "1 s#^.*#$YEAR/$MONTH/$DAY#" $YEAR/$MONTH/$DAY/record1
done
done
echo " "
done
注意:将脚本保存在文件树上方的目录中并按如下方式运行:
~/tree-of-files $ ../change-dates.sh
Processing year 2014 month 06 day 02
Processing year 2017 month 06 day 02
Processing year 2018 month 06 day 02
Processing year 2033 month 06 day 02
~/tree-of-files $
答案3
现有方法略有不同:使用假定 YYYY/MM/DD 目录格式的通配符模式循环遍历文件;在每个文件上,使用将ed
第一行更改为包含目录结构的相应名称:
for file in [0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]/*
do
[ -f "$file" ] || continue
ed -s "$file" <<< $'1c\n'"${file%/*}"$'\n.\nw\nq'
done
该ed
命令以具有以下组件的此处字符串形式给出:
1c
-- 将第 1 行更改为 ...${file%/*}
-- 删除最后一个正斜杠之后产生的变量的参数扩展file
(仅保留时间戳/目录结构部分).
-- 结束c
hange命令w
-- 将文件写入磁盘q
——退出编辑