ファイルからコピーコマンドを実行する

ファイルからコピーコマンドを実行する

DE_CopyOldToNew.txt古いファイル名を新しいファイル名にコピーするための複数のコピーコマンドを含むファイルがあります。

ファイルには次の行が含まれています。

cp /migrationfiles/Company\ Name\ GmbH/2014.138_Old\ File\ Name.pdf /appl/data/docs/202403/DE_2014.138_NewFile_1.pdf
cp /migrationfiles/Company\ Name\ GmbH/2014.139_Old\ File\ Name.pdf /appl/data/docs/202403/DE_2014.139_NewFile_1.pdf

私のシェルスクリプトでは、各行を繰り返し実行します。

echo "Start!"
while read -r line
do
  command "$line"
done < /tmp/DE_CopyOldToNew.txt

スクリプトの実行時に読み取った各行について、次のようになります。

 : No such file or directory6: cp /migrationfiles/Company\ Name\ GmbH/2014.138_Old\ File\ Name.pdf /appl/data/docs/202403/DE_2014.138_NewFile_1.pdf

プロンプトで手動で行を実行すると、エラーなしでうまく機能します。

答え1

問題は、行全体を次のように読み取ることです。一つシェル変数をline選択してから引用符を使用します(例:as "$line")。

シェル変数を扱うとき、特にスペースやその他の「問題のある」文字を含むファイル名を処理する場合、二重引用符は通常正確ですが、この場合は次のことを意味します。ワイヤーcp命令で構成そしてその主張ステートメントは単一のシェルトークンとして扱われますcommand

これは、ループでcp引数/migrationfiles/Company\ Name\ GmbH/2014.138_Old\ File\ Name.pdfのあるコマンドを実行せず、/appl/data/docs/202403/DE_2014.138_NewFile_1.pdfシェルが次の実行可能ファイルを実行しようとしていることを意味します。

cp /migrationfiles/Company\ Name\ GmbH/2014.138_Old\ File\ Name.pdf /appl/data/docs/202403/DE_2014.138_NewFile_1.pdf

コマンドと引数を区別するために使用されるスペースは、コマンド名の一部として解釈されます。もちろん、この実行可能ファイルは存在しません。

あなたができることは、この行を次の3つの変数として読むことです。

echo "Start!"
while read cmd arg1 arg2
do
  command "$cmd" "$arg1" "$arg2"
done < /tmp/DE_CopyOldToNew.txt

構造は常に例に示されている形式を取ると仮定します。

ノートこのreadコマンド確かにこの-rオプションは、次のスペースがエスケープ文字として解釈されるのを無効にするために含まれています\。ただし、ここでこれを行うにはシェルが必要です。

答え2

あなたは言う、

DE_CopyOldToNew.txt古いファイル名を新しいファイル名にコピーするための複数のコピーコマンドを含むファイルがあります。

...そしてあなたはこのコマンドを実行したいと言いましたcp

ラッキーです。これは、シェルによって順番に実行されるコマンドセットを含むファイルであるシェルスクリプトがあるためです。あなたがすべきことは、シェルにスクリプト内のコマンドを実行させることだけです。

sh DE_CopyOldToNew.txt

これにより、デフォルトのシェルが起動し、shファイルの内容がコマンドごとに実行されます。

答え3

TXTファイルが何もせずにデータソースとして扱うので、スクリプトを使用して実行する必要があるだけでなく、データの制御にも使用できます。

# Read each line of the file
while IFS= read -r line; do
    # Get the files using awk with ' /' as separator.
    # $line could have escaped spaces with '\ ' so we use parameter substitution →
    # → to substitute them to unescaped spaces: "${line//\\ / }".
    source_file=$(awk -F' /' '{ print "/"$2 }' <<<"${line//\\ / }") # source file
    destination=$(awk -F' /' '{ print "/"$3 }' <<<"$line") # destination
    
    # For example you can control that the source file exists
    if [[ ! -f "$source_file" ]]; then
        echo "The file $source_file does not exists!"
        exit
    fi
    
    # The cp command is executed here
    cp "$source_file" "$destination"
done </tmp/DE_CopyOldToNew.txt

関連情報