
複数のディレクトリに複数のファイルがあり、各ファイルの最初の行に間違った日付があります。 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 {} +
これは解決策の最初の変形と本質的に同じループに従う。
答え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
(タイムスタンプ/ディレクトリ構造部分のみが保持されます)。.
--hangec
コマンドの終了w
--ディスクにファイルを書き込むq
——編集終了