对多个目录中的文件使用 sed

对多个目录中的文件使用 sed

我在多个目录中有一堆文件,每个文件的第一行的日期不正确。我正在尝试编写一个涉及 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"

cin 命令将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(仅保留时间戳/目录结构部分)
  • .-- 结束change命令
  • w-- 将文件写入磁盘
  • q——退出编辑

相关内容