複数のディレクトリのファイルにsedを使用する

複数のディレクトリのファイルにsedを使用する

複数のディレクトリに複数のファイルがあり、各ファイルの最初の行に間違った日付があります。 sedとforループを含むスクリプトを作成しようとしています。

各ファイルは、正しい日付で構成された独自のディレクトリにあります。たとえば、ファイルが./2014/06/02/record1にあり、最初の行の日付を「2014/06/02」に変更したいとします。

多くのファイルがあり、それぞれに独自のディレクトリがあります。 sedとforループを使用してこれをどのように達成できますか?

ベストアンサー1

すべてのファイルを繰り返すには、たとえば親ディレクトリにあり、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値が既存の一般ファイルのパス名(またはそのファイルへのシンボリックリンク)であることを確認することです。パターンが何も一致しない場合、デフォルトでは拡張されていません(ほとんどのシェルで)。テストによってこの事実が明らかになります。

$pathname上記のループからディレクトリパスを取得するには:

dirpath=$( dirname "$pathname" )

または

dirpath=${pathname%/*}

このdirnameユーティリティは、指定されたパス名のディレクトリパスである文字列を返します。この変数置換バリアントは、最後の変数のすべてを/削除します$pathname。この場合、両方のコマンドは同じ結果を生成しますが、一般的に使用する方が安全です(変数置換が返されるのではなく、指定された文字列をdirname返します)。aa/b/a/b

atファイルの最初の行を$pathnamein文字列に置き換えるには$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 {} +

これは解決策の最初の変形と本質的に同じループに従う。

おすすめ記事