必要に応じてバックスラッシュを含むファイルのリストを変数にどのように保存できますか?

必要に応じてバックスラッシュを含むファイルのリストを変数にどのように保存できますか?

主な問題:

バックアップを実行するスクリプトを作成しています。以下のファイルリストを作成します。

LISTOFFILES=$(find ~ \( -name '*.[pP][dD][fF]' -o -name '*.[oO][dD][tT]' \))

この変数はLISTOFFILESおおよそ次を格納します。

/home/user/file1.pdf /home/user/file2.odt /home/user/Python Tutorial.pdf

次のステップは次のとおりです。

tar cvf backup.tar $LISTOFFILES

Bashの応答は次のとおりです。

/home/user/file1.pdf
/home/user/file2.odt
/home/user/Python: Cannot stat: No such file or directory
tar: Tutorial.pdf

私はBashが仮定しPythonTutorial.pdf別のファイルであることを知っています。

バックスラッシュを含むファイルのリストを作成する方法はありますか?それともパイプで使用するようにfind変更する必要がありますか?ls

私はあなたのアドバイスとアドバイスを読みたいです。

私の他の質問:

この質問に対する答えは重要ではありませんが、ヒントが役に立つかもしれません。

ファイルパスではなくファイル名のみを含むファイルを一覧表示するにはどうすればよいですか?

例:file/home/user/file

find成功せずにコマンドpruneとオプションを試してみましたpath

答え1

主な問題については別のアプローチを取る必要があります。あなたのアプローチは、すべてのファイルを$ LISTOFFILESの単一の文字列に入れることです。その後、アクセス時に引用符を使用しないため、スペースで区切られた結果が表示されます。

希望の結果を得るための最も簡単な方法は次のとおりです。

find ~ \( -name '*.[pP][dD][fF]' -o -name '*.[oO][dD][tT]' \) -print0 | xargs -0 tar cvf backup.tar

私たちがすることは find を実行し、各結果を NULL 文字 (-print0 部分) に分離するだけです。その後、findの出力はxargsにパイプされ、NULL文字で区切られたファイルのリストを読み取り(-0パラメーターはxargsにこれを行うように指示します)、ファイルのリストを「tar」に引数として渡します。

find2番目の質問:コマンドからファイル名を取得するには、printfを使用します。

find /path/to -printf '%f\n'
file.txt

単にfindではなく一般的な意味であればbasename

# basename /path/to/file.txt
file.txt

basename はまさにそのことだけを行うように設計されており、他のことは行いません。

答え2

試みが失敗した理由と回避策

返されたファイル名のリストを蓄積できますが、findファイル名に改行がなく、予防措置を取る場合にのみ可能です。

$LISTOFFILES次のように引用符なしでコマンド置換または変数拡張を作成すると、シェルは次を実行します。噴射そしてワイルドカード(ワイルドカード拡張)結果について。

規則:コマンドの置換と変数の拡張は常に二重引用符で囲みます。
例外:二重引用符を省略する理由と、それでも安全な理由を理解する場合。

ここでは、トークン化は文字列を改行区切りのビットに分割するため、二重引用符を削除する必要があります。ただし、デフォルトでは他の空白文字にも分割されます。したがって、安全を確保し、ワイルドカードをオフにする必要があります。設定で電子を実行できます。IFS変える単一の改行文字に変換し、後者は呼び出してset -f

IFS='
'
set -f
tar cvf backup.tar $LISTOFFILES

バックスラッシュは含まれていません。でファイル名を入力するのではなく、ファイル名を直接入力するときはバックスラッシュを使用してくださいfind

一般的な使用方法find

出力を解析しないでください。findファイルから実行したいコマンドを呼び出すジョブを渡す必要があります-exec。これは、ファイルが多すぎて最大コマンドライン長を超える状況を解決します。プログラムは必要なだけ呼び出されます。

ここでは何度も呼び出すことができないため、もう少し難しいですtar -c(呼び出すたびに新しい空のアーカイブから始めます)。しかし見てくださいTarはディレクトリ構造を維持しながら、ディレクトリ内のすべてのPDFを圧縮します。

より簡単な方法

ファイルが多くなく、ksh93、bash≥4、またはzshを実行している場合は、**ワイルドカードを使用してサブディレクトリに再帰的に移動します。まず、いくつかのシェルオプションを設定する必要があります。

set -o globstar                  # on ksh93
shopt -s globstar -s extglob     # on bash 4
setopt ksh_glob                  # on zsh
tar cvf backup.tar ~/**/*.@(PDF|pdf|ODT|odt)

zshでは、特別な設定なしでパターンを~/**/*.(PDF|pdf|ODT|odt)setopt extglob~/**/(#i)*.(pdf|odt)

またはあなたは使用することができます公園:

pax -w -x ustar -s '/\.pdf$/&/' -s '/\.PDF$/&/' -s '/\.odt$/&/' -s '/\.ODT$/&/' -s '/.*//' ~ >backup.tar

パスプレフィックスが必要ない場合

tarとを使用する方法はいくつかありますが、pax最も簡単な方法は、まずアーカイブしたいディレクトリに変更することです。

( IFS='
'; set -f; cd ~ && tar cvf /path/to/backup.tar $(find . …) )
( cd ~ && pax -w … . ) >backup.tar

答え3

最初の質問:

最初の質問に対する答えは次のとおりです。quotes

する代わりに ->tar cvf backup.tar $LISTOFFILES

これを行う - >tar cvf backup.tar "$LISTOFFILES"

例を見てみましょう。 (ファイルが自分のコンピュータに存在しない場合でも、このデモのためにファイルの1つをインポートしました。受け取ったエラーは引用符を含めて除く)を参照してください。

[jaypal:~] file="/home/user/Python Tutorial.pdf"

[jaypal:~] ls $file
ls: /home/user/Python: No such file or directory
ls: Tutorial.pdf: No such file or directory

2つのファイル/home/user/Pythonがあり、エラーが発生しましたTutorial.pdf。私たちが何を得るのかquote見てみましょうvariable

[jaypal:~] ls "$file"
ls: /home/user/Python Tutorial.pdf: No such file or directory

ファイルにエラーが1つしかありません。/home/user/Python Tutorial.pdf

2番目の質問:

剪定には/path/to/fileいくつかの方法があります。私が一番好きなのですが、awk一つもお見せしますsed

sed方法:

[jaypal:~/Temp] echo "$filename"
/home/user/file1.pdf /home/user/file2.odt /home/user/Python Tutorial.pdf

[jaypal:~/Temp] echo "$filename" | sed 's@/home/user/@@g'
file1.pdf file2.odt Python Tutorial.pdf

次のようにスクリプトに含めることができます。

LISTOFFILES=$(find ~ \( -name '*.[pP][dD][fF]' -o -name '*.[oO][dD][tT]' \) | sed 's@/home/user/@@g' )

ここで覚えておくべきことは、私たちがやっていることですsubstitution。複数のディレクトリのファイルを処理する場合は、多くの置換操作を実行するか(はい!)、次のことが/home/user/できます。nothingfindawk

awk方法:

awk -F"/" '{print $NF}'

そうそう。findすべてのディレクトリまたはそのサブディレクトリのファイルに適用されます。

したがって、スクリプトは次の方法で実装できます。

LISTOFFILES=$(find ~ \( -name '*.[pP][dD][fF]' -o -name '*.[oO][dD][tT]' \) | awk -F"/" '{print $NF}')

その他のヒントとコツ:

これはあなたに役立つと思われるいくつかのランダムなヒントです。

findファイル名は現在持っている名前をinsensitively使用してください。inameこれを見てください -

[jaypal:~/Temp] find . -name "j*.txt"
./jP.txt

[jaypal:~/Temp] find . -iname "j*.txt"
./jj.TXT
./jP.txt

整理/path/to/fileする他の方法basenameは。

[jaypal:~/Temp] filename="/usr/bin/java.pdf"

[jaypal:~/Temp] echo "$filename"
/usr/bin/java.pdf

[jaypal:~/Temp] basename "$filename"
java.pdf

役に立ったことを願っています!

関連情報