主な問題:
バックアップを実行するスクリプトを作成しています。以下のファイルリストを作成します。
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が仮定しPython
てTutorial.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」に引数として渡します。
find
2番目の質問:コマンドからファイル名を取得するには、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/
できます。nothing
find
awk
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
役に立ったことを願っています!