可能なすべてのファイル名を正しく処理することは可能ですか? [閉鎖]

可能なすべてのファイル名を正しく処理することは可能ですか? [閉鎖]

Linuxでは、ファイル名には「スラッシュ」と「ヌル文字」の2文字しか禁止されていません。したがって、すべてのスクリプト言語で特別な意味を持つすべての文字はエスケープする必要がありますが、すべてのエスケープシーケンスはファイル名にも許可されます。悪いことに、bashのいくつかのエスケープ方法は特定の文字だけをエスケープするので、他の多くの文字をエスケープするには、いくつかのエスケープ方法を一緒に使用する必要がありますが、互いに干渉します。ある意味では、一部のコマンドは目的を達成するために特定の文字を使用し、他のコマンドは別の文字を使用するため、ファイルに対するすべての簡単な操作に対してファイル名を別々にエスケープする必要があります。説得力のあるファイル名を安全に区切るためにヌル文字しか使用できませんが、ほとんどのコマンドはヌル文字とは連携しません。悪いことに、基本的にLinuxのすべてはファイルです。したがって、これは迷惑であるだけでなく、セキュリティと信頼性の問題でもあります。 Linuxのほとんどはスクリプトベースなので、非常に欠陥がたくさんあります!

それで、私がどこで間違っているのか教えてください...すべての可能なファイル名を正しく処理することは可能ですか?

言う。もともと私はそう思った。

  1. 特定のパスの下のファイルとフォルダのリスト

  2. 指定された基準(年齢、ファイルモード、またはサイズ)に一致するコンテンツのリストを取得します。

  3. 一致するファイルとフォルダをカテゴリ(映画など)に移動します。テストの複雑さのため、1つのコマンドでこれを行うことは不可能(または実用的)であるため、異なるコマンド間でファイル名を渡す必要があります。 Bashワイルドカードはファイル名にスペースがあるため、最初に削除されます。ワイルドカードは常にスペースを含むファイル名をリストの2つの要素に分割します。それから「検索」を試してみました。これは良いですが、はるかに遅くて使いにくいです。

ファイル名にどの文字があるかわからないため、ファイル名をエスケープするために特殊文字を使用することはできません。いくつかのテストを経た後、どのキャラクターが登場するのかは時間の問題であることがわかりました。

私は次のようにフィルタを定義してみました。 audio_ext=(*.mp3 *.wav *.ogg *.mid *.mod *.stm *.s3m *.it *.wma *.669 *.ac3) ワイルドカードを使用すると権限が奪われるため、この方法で複数の用途でフィルタを定義することはできません。だからワイルドカードと歴史を無効にしましたset -fH。ワイルドカードがない場合は、手動で拡張する必要があります。

while IFS= read -r -d $'\0'; do list+=("$REPLY") done < <( find . -maxdepth 1 -mindepth 1 ${params[@]} -print0 2>/dev/null )

paramsこのような配列はどこにありますか"-iname" "*.mp3" "-o" "-iname" "*.wav"?これは、ファイル名に "(" が含まれるまで機能します。) ルックアップは、誤った使用に関するエラーを返します。

正直なところ、私は最近まで15年間この作業にバッチスクリプトを使用してきました。書き込み時間は午後1~2時程度です。欠点とファイル名の問題がありますが、!通常は動作します。私はほぼ2ヶ月間bashで書こうとしました。醜くて複雑でバグでいっぱいで、うまく動作しないようです。

ベストアンサー1

単純な。グローブを使用して目的のファイルを選択し、ファイル名を含む変数を参照します。

shopt -s nullglob
for file in ./*.txt; do
    do_something_with "$file"
done

それはすべてです。

詳細は:


アップデート:ワイルドカードはいいえあなたが見る単語分割効果を引き起こします。変数を参照できません。

次の方法で条件に合ったファイル情報を取得できます。stat

read size mtime < <(stat -c "%s %Y" "$file")
[[ $size -gt 1000 ]] && echo "too big"
[[ $mtime -lt $(date -d yesterday +%s) ]] && echo "too old"

更新2:多くの特殊文字を含むファイル名を作成するには、さまざまな引用メカニズムを混在させる必要がありますが、ファイルに対してすべての操作を実行することは依然として可能です。

$ filename='~ASDFzxcv!@#$%^&*()_+[]\{}|;:",.<>?`'"'"$' \a\t\n\r\f'".txt"
#          ^^ single quoted part ^^^^^^^^^^^^^^^^   
#                             double quoted part ^^^
#                                ANSI-C quoted part ^^^^^^^^^^^^^^

$ echo "$filename"
~ASDFzxcv!@#$%^&*()_+[]\{}|;:",.<>?`'   

.txt

$ printf "%q\n" "$filename"
$'~ASDFzxcv!@#$%^&*()_+[]\\{}|;:",.<>?`\' \a\t\n\r\f.txt'

$ date > "$filename"

$ cat "$filename"
Thu Apr 12 15:14:29 EDT 2018

$ ls -lt
total 3836
-rw-rw-r-- 1 jackman jackman      29 Apr 12 15:14 ~ASDFzxcv!@#$%^&*()_+[]\{}|;:",.<>?`' ?????.txt

$ ls -lt --show-control-chars
total 3836
-rw-rw-r-- 1 jackman jackman      29 Apr 12 15:14 ~ASDFzxcv!@#$%^&*()_+[]\{}|;:",.<>?`'     

.txt

出力がls端末以外のもの(ファイルやパイプなど)にリダイレクトされる場合は、デフォルトで--show-control-charsこのスタイルを使用します。を実行すると、これを確認できますls -lt | cat。  lsたとえば、他の表示オプションがあります。--quoting-style=WORD

おすすめ記事