bashシェルスクリプトから複数のワイルドカードに変数を拡張するには、mv /renameを使用します。

bashシェルスクリプトから複数のワイルドカードに変数を拡張するには、mv /renameを使用します。

私は、データファイルで指定されたパラメータに基づいて静的フォルダ内のファイルを移動するLinux用のbashシェルスクリプトを作成しました。

私が経験している問題を示すために、スクリプトを再現可能な最小限の例に縮小しました。

#!/bin/bash
while IFS=" " read -r fldr matchStr
do
    perlExp=\'s/^/\\/home\\/test\\/alpha\\/"$fldr"\\//\'
    fullmatchStr=testfile\ -\ "$matchStr"\ -\ *.txt
    rename --verbose "$perlExp" ${fullmatchStr}
done < test.dat

(私は元の代わりにmv使用を開始しましたが、両方のコマンドのrenameいずれかを使用できます。)

スクリプトは、test.dat次の構文で構成されるテキストファイルを読み込みます。

folderName matchStr
...

このファイルの簡単な例test.dat

test001 *.foo.bar
test002 *.foo.baz
test003 bar.*.baz

このデータファイルにワイルドカードが許可され、スクリプトがワイルドカードをサポートすることが重要です。また、ファイル名のスペースをサポートする必要があります。

移動するファイルのファイル名の例:

testfile - linux.foo.bar - 10101010 10101010.txt
testfile - unix.foo.bar - 01010101 10101010.txt
testfile - ubuntu.foo.baz - 10101010 01010101.txt
testfile - debian.foo.baz - 10101010 00000000.txt
testfile - bar.linus.baz - 11111111 01010101.txt

上記のtest.datファイルが与えられたら、これらのファイルを個別に次のフォルダに移動する必要があります。

/home/test/alpha/test001
/home/test/alpha/test001
/home/test/alpha/test002
/home/test/alpha/test002
/home/test/alpha/test003

以下を含むいくつかの関連QAを読みました。

しかし、まだ希望の結果が得られませんでした。エラーは発生しませんでしたが、ファイルは移動されませんでした。

このコードが期待どおりに機能するようにどのように改善できますか?

答え1

Perlベースのコードを使用している場合rename(そうです)、Perlコードを書くためにシェル文字列を使用しないことをお勧めします。シェルコードでできることを行うには、Perlコードを直接使用してください。

この場合、ループ内で次のことを行います。

IFS=
target="/home/test/alpha/$fldr/" rename --verbose 's/^/$ENV{target}/' "testfile - "$matchStr" - "*.txt

targetここで置き換えるのは、コマンドに設定した環境変数の値なので、renamePerlコードを使用して簡単に取得できます。また、IFSを空の文字列に設定すると単語の区切りが無効になり、$matchStrワイルドカードを安全に使用できます。 (しかし、ここではおそらく必要ありません。引用符がない項目のみを使用できます。結果である$matchStrため、単語の区切りについて心配する必要はありませんが、IFS=" " read -rタブが含まれていることはほとんどありません...)

答え2

主に効果がなく、エラーがない理由に焦点を当てるには、次の手順を実行します。

perlExp=\'s/^/\\/home\\/test\\/alpha\\/"$fldr"\\//\'
rename --verbose "$perlExp" ${fullmatchStr}

perlExp一重引用符を含む文字列に割り当てられ、渡されますperl's/^/\/home\/test\/alpha\/...\//'これは、単一の文字列定数を含む有効なPerl式です。何の効果もないので、rename変更は適用されません。

つまり、シェル変数に含まれる引用符は単なるデータであり、シェルは変数拡張結果を再解析しません。したがって、値に追加の引用符を追加しないでください。foo="'foo bar'"; echo "$foo"印刷と同じ操作を実行する方法を検討してください。echo "'foo bar'"'foo bar'


別の質問として、fullmatchStr=testfile\ -\ "$matchStr"\ -\ *.txt変数が文字列に設定され、testfile - ... - *.txtスペースとglob文字の両方が含まれている場合は、引用符なしで展開すると、最初に、、で区切られ、globが拡張され、ファイルtestfile-で終わるすべて...の項目と一致します。この問題を解決するには、空の文字列に設定して単語の区切りを無効にする必要があります。.*.txt.txtIFS

Perlを使用するとs///、さまざまな文字を区切り文字として使用することもできます。


したがって、次のように動作できます。

#!/bin/bash

# disable word splitting in the script due to the unquoted expansion
IFS=

# the IFS assignment below only applies to 'read'
while IFS=" " read -r fldr matchStr
do
    perlExp='s#^#/tmp/test/alpha/'"$fldr"'/#'
    fullmatchStr="testfile - $matchStr - *.txt"
    rename --verbose "$perlExp" ${fullmatchStr}
done < test.dat

しかし正直、Muluのソリューション環境を介して文字列を渡す方法は、コードにデータを挿入するときに必要な注意と2段階の引用を避け、特にファイルからPerlにインポートされたディレクトリ名が何であるかを気にする必要がないため、より良い方法です。特殊文字が含まれています。

関連情報