私のフォルダ名がこれで終わるのはなぜですか?スクリプトを使用してこの問題を解決するにはどうすればよいですか?

私のフォルダ名がこれで終わるのはなぜですか?スクリプトを使用してこの問題を解決するにはどうすればよいですか?

申し訳ありません。他に答えがある場合は、私の質問をどのように検索するのかわかりません。

Redhat Linux HPCサーバーでいくつかのシミュレーションを実行していますが、出力を保存するためにフォルダ構造を処理するコードに不幸なバグがあります。フォルダを作成する私のMATLABコードは次のとおりです。

folder = [sp.saveLocation, 'run_', sp.run_number, '/'];

sp.run_number整数はどこにありますか?文字列に変換するのを忘れましたが、何らかの理由でmkdir(folder);matlabで実行しても成功します。実際、シミュレーションはスムーズに実行され、データは一致するディレクトリに保存されます。

これで、フォルダ構造を照会/印刷すると、次のようになります。

  • タブオートコンプリートを使用しようとすると:run_ run_^A/ run_^B/ run_^C/ run_^D/ run_^E/ run_^F/ run_^G/ run_^H/ run_^I/
  • 私が使用するときlsrun_ run_? run_? run_? run_? run_? run_? run_? run_? run_? run_?
  • rsyncを使用してMacに転送すると、--progressオプションは次のように表示されます。run_\#003/(私の家では)3桁の数字で埋められた整数と一致する数値なsp.run_numberので、10番目の実行は次のようになります。run_\#010/
  • Finderでフォルダを見るとrun_ run_ run_ run_ run_ run_ run_ run_ run_ run_?
  • 見ているこれ質問を受け、私が得たコマンドを使用してls | LC_ALL=C sed -n l
run_$
run_\001$
run_\002$
run_\003$
run_\004$
run_\005$
run_\006$
run_\a$
run_\b$
run_\t$
run_$

cdこれらの表現を使用すると、フォルダに入ることはできません。

このようなフォルダは何千ものあるため、この問題を解決するにはスクリプトが必要です。次のオプションのうち、フォルダを正しく表現したものは何ですか? bashスクリプトを使用して正しい形式の名前に名前を変更できるように、プログラムでこれらのフォルダを参照するにはどうすればよいですか?気になってそうだが、一体どうやってこんなことが起きたのでしょうか?

答え1

Perlユーティリティ(またrenameはとも呼ばれる)を使用してディレクトリの名前を変更できます。prenamefile-rename

メモ:または他のバージョンrenameと混同しないでください。util-linux

rename -n 's/([[:cntrl:]])/ord($1)/eg' run_*/

これはPerlのord()機能を使用して、ファイル名の各制御文字をその文字の序数で置き換えます。たとえば、^A1になり^B2になります。

この-nオプションは、コンテンツを表示するためのテスト実行に使用されます。rename 会議許可されている場合は、そうしてください。実際に名前を変更するには、それを削除するか、-v詳細な出力に置き換えてください。

e操作の修飾子は、s/LHS/RHS/egperlにRHS(代替)をPerlコードで実行させ、$1LHSの一致データ(制御文字)です。

ファイル名にゼロで埋められた数字を使用するには、ord()たとえばsprintf()

$ rename -n 's/([[:cntrl:]])/sprintf("%02i",ord($1))/eg' run_*/ | sed -n l
rename(run_\001, run_01)$
rename(run_\002, run_02)$
rename(run_\003, run_03)$
rename(run_\004, run_04)$
rename(run_\005, run_05)$
rename(run_\006, run_06)$
rename(run_\a, run_07)$
rename(run_\b, run_08)$
rename(run_\t, run_09)$

上記の例はうまくいきますそして、もし sp.run_numbermatlabスクリプトでは、その範囲は0..26です(したがって、ディレクトリ名に制御文字を生成します)。

1 バイト文字 (たとえば、0..255 から始まる) を処理するには、次を使用できます。

rename -n 's/run_(.)/sprintf("run_%03i",ord($1))/e' run_*/

255以上が可能な場合は、代わりにsp.run_numberPerlの関数を使用する必要があります。 matlabが変換されていないintを文字列として出力する方法がわからないので、実験する必要があります。詳細より。unpack()ord()perldoc -f unpack

たとえば、次のコードは8ビットと16ビットの符号なし値を解凍し、5ビット幅でゼロパディングします。

 rename -n 's/run_(.*)/sprintf("run_%05i",unpack("SC",$1))/e' run_*/

答え2

気になってそうだが、一体どうやってこんなことが起きたのでしょうか?

folder = [sp.saveLocation, 'run_', sp.run_number, '/'];

sp.run_number整数はどこにありますか?文字列に変換するのを忘れましたが、何らかの理由で実行中ですmkdir(folder)。 (matlabで)まだ成功しています。

mkdir([...])したがって、Matlabでは配列のメンバーがリンクされ、ファイル名を文字列にするようです。しかし、あなたはそれに数字を与え、数字はコンピュータの実際の文字です。したがって、sp.run_numberwas は1value ロールを提供し、1value ロール2などを提供します。

これは制御文字であり、印刷可能な記号はなく、端末に印刷すると他の結果が発生します。したがって、通常、さまざまな種類のエスケープ文字で表されます。 (\0018進数)、\x01(16進数)は^Aすべて値を持つ文字の一般的な表現です1。 0 値文字は若干異なります。 C および Unix システムコールで文字列の終わりを表示するために使用される NUL バイト。

31以上に上がると、印刷可能な文字が見え始めます。 32はスペース(あまり明確ではありません)、33 = !、34 ="などです。

だから、

  • run_ run_^A/ run_^B/- 最初のrun_バイトは、文字列が終わるゼロバイトに対応します。他のものは、シェルがディスプレイ制御コードの使用を好むことを示します^A。この表記法は、値が1のcharを入力することもできることを示唆しています。ただし、少なくともBashでは、Ctrl-Aこれを制御文字として解釈するのではなく、リテラルとして解釈するようにシェルに指示する必要があります。Ctrl-V Ctrl-A

  • ls:run_ run_? run_?-ls印刷できない文字を端末に印刷するのが好きではなく、それを疑問符で置き換えます。

  • rsync: run_\#003/— これは私にとって新しいものですが、アイデアは同じです。バックスラッシュはエスケープを表示し、残りは文字の数値です。私が見るにはここにある数字がより一般的な数字のように8進数になっているようです\003

  • ls | LC_ALL=C sed -n l... run_\006$ run_\a$ run_\b$ run_\t$- コマンドを使用して、\aそれぞれ警告(リング)、バックスペース、およびタブのCエスケープ文字です。彼らの数字は7、8、9なので、なぜ一番後ろにあるのかは明らかです。これらのCエスケープを使用することは、制御文字を表示する別の方法です。次のドル記号は行の終わりを示します。\b\t\006

の場合、cd私の仮定が正しいと仮定すると、奇妙な末尾の文字がない単一のディレクトリにcd run_移動する必要があり、cd run_?疑問符は単一の文字と一致するグローバル文字であり、一致するファイル名が複数あるため、エラーが発生するはずです。cd一つだけ期待してください。

次のオプションのうち、フォルダを正しく表現したものは何ですか?

これらすべてはある意味では...

Bashでは、 \000特殊文字は、引用符内のエスケープ文字(8進数)または文字値27(ESC)に対応するディレクトリを使用して表現できます。 (Bashは10進エスケープをサポートしていないようです。)\x00$'...'$'run_\033$'run_\x1b'

casの答えには名前を変更するスクリプトがあるので、そこには行きません。

答え3

最も簡単な方法は、事故が発生したのと同じ環境で誤ったファイル名と正しいファイル名を生成し、フォルダを正しい名前に移動/変更することです。

既存の名前間の競合を避けるために、別のターゲットフォルダを使用するのが最善です。

./saveLocationA/wrongname1 -> ./saveLocationB/correctname1
./saveLocationA/wrongname2 -> ./saveLocationB/correctname2
./saveLocationA/wrongname3 -> ./saveLocationB/correctname3

可能であれば、スクリプトを修正して再実行したいと思います。後で奇妙なエラーを修正すると、より費用がかかり、新しい問題が発生する可能性があります。

頑張ってください!

関連情報