質問

質問

私はシェルスクリプトの新しいスキルを学びようとしています。先生からファイルを新しいディレクトリに移動する方法についての講義を聞きました。

質問

ファイルパターンがあります

A_20180423_0015  B_20180501_0045  C_20180426_0045  

/new/destpath/A/20180423/0015,0030,0045 などのディレクトリにファイルを移動する場合は、各ディレクトリに 3 つのファイルがあります。

私の台本では

 #! /bin/bash
cd /app/Moving/DEST_PATH
mkdir A B C D
cd /app/Moving/DEST_PATH/A
MakesubA=$(for itype in A;do for ((i=1;i<=10;i++));do for ((itime=15;itime<=45;itime=itime+15));do mkdir ${itype}_$(date --date "${i} day ago" +"%Y%m%d")_00${itime} ;done;done;done)
cd ..
cd /app/Moving/DEST_PATH/B
MakesubB=$(for itype in B;do for ((i=1;i<=10;i++));do for ((itime=15;itime<=45;itime=itime+15));do mkdir ${itype}_$(date --date "${i} day ago" +"%Y%m%d")_00${itime} ;done;done;done)
cd ..
cd /app/Moving/DEST_PATH/C
MakesubC=$(for itype in C;do for ((i=1;i<=10;i++));do for ((itime=15;itime<=45;itime=itime+15));do mkdir ${itype}_$(date --date "${i} day ago" +"%Y%m%d")_00${itime} ;done;done;done)
cd ..
cd /app/Moving/DEST_PATH/D
MakesubD=$(for itype in D;do for ((i=1;i<=10;i++));do for ((itime=15;itime<=45;itime=itime+15));do mkdir ${itype}_$(date --date "${i} day ago" +"%Y%m%d")_00${itime} ;done;done;done)
cd ..

私はループなどを使って調べようとしましたが、ディレクトリごとに各ファイルを選択するためにどのようなものを使うべきかわかりません。

答え1

ファイルには、デフォルトでファイル名にエンコードされたターゲットパスがあります。

呼び出されるファイルは元のファイル名と同じパス名ですが、下線がスラッシュで置き換えられている(ディレクトリ内のファイルの新しい名前であると仮定)A_20180423_0015に移動する必要があります。A/20180423/00150015A/20180423

これは、この練習が文字列の文字置換に関するものです。

ターゲットはすでにファイルのファイル名にエンコードされているため、すべての可能な日付に対してターゲットディレクトリを繰り返し作成する必要はありません。

元のファイルがどこにあるか、または元のファイルを[A-Z]_*_*パターンとして使用して現在のディレクトリで一致させることができるかどうかは完全にはわかりません(できると仮定します)。

for source_filename in [A-Z]_*_*; do
    target_pathname=${source_filename//_//}
    mkdir -p "${target_pathname%/*}"
    mv "$source_filename" "$target_pathname"
done

私たちが始まると

.
|-- A_20180423_0015
|-- B_20180501_0045
`-- C_20180426_0045

0 directory, 3 files

...上記のコードを実行すると、次のような結果が得られます。

.
|-- A/
|   `-- 20180423/
|       `-- 0015
|-- B/
|   `-- 20180501/
|       `-- 0045
`-- C/
    `-- 20180426/
        `-- 0045

6 directories, 3 files

コメントコード:

# Loop over all names in the current directory that matches the given pattern.
for source_filename in [A-Z]_*_*; do
    # Replace all underscores in the found name with slashes.
    # We use bash's ${parameter//pattern/replacement} pattern substitution
    # to do this.
    # If you need to append a path to this, just do so with
    #    target_pathname="/some/path/${source_filename//_//}"
    target_pathname=${source_filename//_//}

    # Make sure that the target directory exists.
    # With ${target_pathname%/*} we remove the filename component of
    # the target pathname to get the directory of the destination file.
    # You may change this to the following if you wish:
    #     mkdir -p "$( dirname "$target_pathname" )"
    mkdir -p "${target_pathname%/*}"

    # Move the file into place.
    mv "$source_filename" "$target_pathname"
done

質問を誤って理解してファイルが元のファイル名を保持する必要がありますが、ファイル名に対応するディレクトリに移動する必要がある場合(例:A_20180423_0015に移動する必要がある場合A/20180423/0015/A_20180423_0015)、上記のコードで数文字を変更するだけです。

mkdir -p "${target_pathname%/*}"

に変更

mkdir -p "$target_pathname"

この変化は私たちをもたらすでしょう

.
|-- A/
|   `-- 20180423/
|       `-- 0015/
|           `-- A_20180423_0015
|-- B/
|   `-- 20180501/
|       `-- 0045/
|           `-- B_20180501_0045
`-- C/
    `-- 20180426/
        `-- 0045/
            `-- C_20180426_0045

9 directories, 3 files

ソースファイルが現在のディレクトリ以外のディレクトリにある場合:

for source_pathname in /some/source/path/[A-Z]_*_*; do
    source_filename=${source_pathname##*/}
    target_pathname="some/target/path/${source_filename//_//}"
    mkdir -p "$target_pathname"
    mv "$source_pathname" "$target_pathname"
done

関連情報