0

これらの行は、コピーしてシェルに貼り付けると機能しますが、スクリプトでは機能しません。

ls -l file1 > /path/`echo !#:2`.txt
ls -l file2 > /path/`echo !#:2`.txt

 

ls -l file1 > /path/$(echo !#:2).txt
ls -l file2 > /path/$(echo !#:2).txt

bashスクリプトでこれを行うための構文は何ですか?

可能であれば、1 つのファイルと、フォルダー内の同じ拡張子を持つすべてのファイルに対してこれを行う方法を知りたいです。

4

2 に答える 2

3

非対話型シェルでは、履歴の展開が無効になっています。

次の 2 行をスクリプトに追加して有効にします。

set -o history
set -o histexpand
于 2013-05-31T23:31:21.787 に答える
1

(更新:元の質問を、スクリプト内の現在のコマンドへの引数ではなく、スクリプトへの引数を参照していると誤解しました。これは書き直された回答です。)

@choroba が言ったように、スクリプトでこのようなことを行うのは実際には正しい方法ではないため、履歴はスクリプトでデフォルトで無効になっています。

スクリプトでこのようなことを行うための推奨される方法は、問題の項目 (この場合はファイル名) を変数に格納し、コマンドで複数回参照することです。

fname=file1
ls -l "$fname" > "/path/$fname.txt"

スペースやその他のシェルのメタ文字が含まれている場合の問題を回避するために、ほとんどの場合、変数参照を二重引用符で囲む必要があることに注意してください (上記のように)。複数のファイルに対してこれを行う場合は、forループを使用します。

for fname in *; do   # this will repeat for each file (or directory) in the current directory
    ls -l "$fname" > "/path/$fname.txt"
done

現在のディレクトリ以外の場所にあるファイルを操作したい場合、状況はもう少し複雑になります。を使用できます/inputpath/*が、各ファイル名とともにパスが含まれます (たとえば、「/inputpath/file1」、「/inputpath/file2」などでループを実行します)。それを出力で直接使用すると、リダイレクトすると、次のような結果が得られます> /path/inputpath/file1.txt(つまり、2 つの異なるパスが一緒に追加されます)。この場合、basenameコマンドを使用して、出力目的で不要なパスを取り除くことができます。

for fpath in /inputpath/*; do
    ls -l "$fpath" > "/path/$(basename "$fpath").txt"
done

特定の拡張子を持つファイルのリストが必要な場合は、必要に応じて*.fooまたは/inputpath/*.fooを使用してください。ただし、この場合、「file1.foo.txt」などの名前のファイルに出力されることになります。積み重ねられた拡張機能が必要ない場合はbasename、それをトリミングするオプションもあります。

for fpath in /inputpath/*.foo; do
    ls -l "$fpath" > "/path/$(basename "$fpath" .foo).txt"
done

最後に、(実際の操作がどれほど複雑であるか、スクリプトで複数回発生するかどうかに応じて) これを関数でラップし、それを使用する方が適切な場合があります。

doStuffWithFile() {
    ls -l "$1" > "/path/$(basename "$1" "$2").txt"
}

for fpath in /inputpath/*.foo; do
    doStuffWithFile "$fpath" ".foo"
done
doStuffWithFile /otherpath/otherfile.bar .bar
于 2013-05-31T23:20:58.950 に答える