複数のディレクトリに複数のファイルがあり、各ファイルの最初の行に間違った日付があります。 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
返します)。a
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 {} +
これは解決策の最初の変形と本質的に同じループに従う。