Unixシェルスクリプト、空白のパラメータ

Unixシェルスクリプト、空白のパラメータ

というシェルスクリプトを作成する必要がありますchExt.sh。ファイル拡張子を受け入れてから、複数のファイルを受け入れます。次に、ファイル拡張子を変更するか、ファイルが存在しないと宣言する必要があります。

./chExt.sh txt ocelot.cpp ../otherFolder/file.H cat.dog.TXT king cobra.dat自動テスターテストの一般的なアイデアです。問題は、名前にスペースが含まれているファイルを処理する方法がわからないことです。

私のコードは次のとおりです

newExt="$1"
shift
for x in $*
do
    fileName="$x"
    if test -f "$fileName";
    then
        name=$(echo "$fileName" | rev | cut -f 2- -d '.' | rev)
        newName="$name.$newExt"
        if test "$newName" != "$fileName";
        then
            mv "$x" "$newName"
        fi
    else
        echo "$fileName: No such file"
    fi
done

ベストアンサー1

ファイル名を引用しないと、シェルはこれが2つの引数(および)foo bar.txtではなく1つの引数であることを知りません。したがって、次のようにスクリプトを呼び出す必要があります。foobar.txt

./chExt.sh txt ocelot.cpp ../otherFolder/file.H cat.dog.TXT "king cobra.dat"

次の問題は、変数が展開されると結果の値が空のスペースで分割(または$IFS変数に設定された値)。したがってfor i in $*、を書くと$*スペースが拡張され分割されます。だからそれは一度の繰り返しと次の繰り返しになります$i。回避策は、拡張したい変数が分割されないように引用することです。kingcobra.txt

これは次の質問につながります。$*間の違い$@。使用すると、"$*"引数はすべて1つの長い文字列として扱われます。

$ cat foo.sh
#!/bin/sh
for i in "$*"; do
    echo "$i"
done
$ foo.sh foo "bar baz"
foo bar baz

上記を以下と比較してみてください。

#!/bin/sh
for i in "$@"; do
    echo "$i"
done
$ foo.sh foo "bar baz"
foo
bar baz

ご覧のとおり、使用すると"$@"予想される効果があり、スペースを含む引数を含む各入力引数は個別に処理されます。

最後に、スクリプトは-オプションに対応する文字と次に始まるファイル名もブロックします(たとえば、名前付きechoファイルを試してみてください)。-new拡張を削除するより良い方法は、シェルのデフォルトの拡張を使用することです。文字列操作関数。変数の末尾から、${var%.*}aとゼロ以上の文字に一致する最も短い文字列を削除します。.つまり、拡張です。次に、次から始まるファイル名も処理できるように、オプションの終わりと引数の始まりを示すためにto--を追加する必要があります(ガイド10を参照)。mv-ここ)。

したがって、改善され動作するスクリプトのバージョンは次のとおりです。

#!/bin/sh
newExt="$1"
shift
for fileName in "$@"
do
    if test -f "$fileName";
    then
    #    name=$(echo "$fileName" | rev | cut -f 2- -d '.' | rev)
    name=${fileName%.*}
        newName="$name.$newExt"
        if test "$newName" != "$fileName";
        then
            mv -- "$fileName" "$newName"
        fi
    else
        printf '%s: No such file\n' " $fileName"
    fi
done

追加資料:

おすすめ記事