폴더 이름이 왜 이렇게 되었습니까? 그리고 스크립트를 사용하여이 문제를 어떻게 해결할 수 있습니까?


15

다른 곳에서 답변이 있으면 죄송합니다. 문제를 검색하는 방법을 모르겠습니다.

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/
  • 내가 사용할 때 ls: run_ run_? run_? run_? run_? run_? run_? run_? run_? run_? run_?.
  • rsync를 사용하여 Mac으로 전송할 때 --progress옵션은 다음 run_\#003/과 같이 표시됩니다 : 등의 숫자 sp.run_number는 3 자리 로 채워진 정수와 일치합니다.run_\#010/
  • 파인더에서 폴더를 볼 때 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 스크립트를 사용하여 올바른 형식의 이름으로 바꾸려면 어떻게해야합니까? 그리고 호기심을 위해서, 어떻게 이런 일이 처음에 일어 났습니까?


4
"자동 완성 탭을 시도 할 때 : ... 입력하려고하면 ..."입력하고 자동 완성을 완료하지 않는 이유는 무엇입니까? 또한 ^A문자 그대로 ^뒤에옵니다 A. 그러나 Ctrl-A (Ctrl-A는 일반적으로 쉘의 바로 가기이므로 Ctrl-V Ctrl-A를 사용하여 입력 할 수 있습니다).
muru

작동하지 않는 @muru ...까지 거리가 멀어 run_입력해야합니다
Phill

내가 편집 한 내용을보기 전에 댓글을 달아 죄송합니다. cd를 통해 나를 안내합니다.
Phill


9
때문에 BTW, MATLAB에서 MKDIR 이런 짓을 왜 "어떤 이유"입니다 유닉스 파일 시스템에있는 파일이나 디렉토리 이름에 잘못된 문자가 NUL와 슬래시가 있습니다 /. 제어 문자를 포함한 다른 모든 문자가 유효합니다. sp.run_number가 0 인 경우 matlab이 어떤 작업을 수행했는지 알 수 없습니다 ( run_NUL 바이트가 디렉토리 이름 문자열을 종료하므로 오류가 발생하거나 중단됩니다 ). 물론 이것은 NUL 바이트가 포함 된 16 비트 (또는 그 이상) 값에서도 문제가 될 수 있으며 matlab을 실행하는 시스템의 엔디안 (endian-ness)에 따라 달라집니다.
cas

답변:


26

perl rename유틸리티 (일명 prename또는 file-rename)를 사용하여 디렉토리 이름을 바꿀 수 있습니다 .

참고 :rename from util-linux또는 다른 버전 과 혼동해서는 안됩니다 .

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

이것은 perl의 ord()기능을 사용 하여 파일 이름의 각 제어 문자를 해당 문자의 서수로 바꿉니다. 예를 들어 ^A1 ^B이되고 2가됩니다.

-n옵션은 무엇을 보여줄 수있는 드라이 실행을위한 rename 것입니다 당신이 그것을 허락한다면 않습니다. -v실제로 이름을 바꾸려면 제거하거나 자세한 출력으로 대체하십시오 .

조작 의 e수정자는 s/LHS/RHS/egperl이 perl 코드로 RHS (대체)를 실행하게 $1하고 LHS에서 일치하는 데이터 (제어 문자)입니다.

파일 이름에 0으로 채워진 숫자를 원하면와 결합 할 수 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)$

위의 예제 는 matlab 스크립트에서 0..26 범위에있는 경우에만 작동 sp.run_number하므로 디렉토리 이름에 제어 문자를 생성했습니다.

1 바이트 문자 (예 : 0..255)를 처리하려면 다음을 사용하십시오.

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

sp.run_number> 255 일 수있는 경우 unpack()대신 펄의 함수 를 사용해야 ord()합니다. matlab이 어떻게 문자열로 변환되지 않은 int를 출력하는지 정확히 알지 못하므로 실험해야합니다. 자세한 내용 perldoc -f unpack을 참조하십시오.

예를 들어 다음은 8 비트 및 16 비트 부호없는 값의 압축을 풀고 너비가 5 자리로 0으로 채워집니다.

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

자세한 내용에 감사드립니다! 나는 -n옵션으로 그것을 시험하려고 노력하고 있지만 그것은 나에게 잘못된 옵션을 말해주고있다-버전 정보는 나에게 rename from util-linux 2.23.2같은 기능을 확신하지 못한다.
Phill

3
버전의 rename유틸리티를 지정한 이유 입니다. util-linux의 기능 rename은 매우 다르고 기능이 훨씬 적으며 명령 행 옵션이 호환되지 않습니다. 데비안이나 그와 비슷한 것을 사용하고 있다면 file-rename패키지를 설치하십시오 . 그렇지 않으면 배포판에 적합한 패키지를 설치하십시오. 이미 설치되어 prename있거나 실행 중이 거나 file-rename그냥 시도하십시오 rename.
cas

네, 그런 경우라고 생각했습니다. 그 중 하나를 작동시킬 수 있는지 살펴 보겠습니다. 도와 주셔서 감사합니다.
Phill

11

그리고 호기심을 위해서, 어떻게 이런 일이 처음에 일어 났습니까?

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

sp.run_number정수는 어디에 있었습니까? 문자열로 변환하는 것을 잊었지만 어떤 이유로 든 실행 중입니다 mkdir(folder). (matlab에서) 여전히 성공했습니다.

따라서 mkdir([...])Matlab에서는 배열의 멤버를 연결하여 파일 이름을 문자열로 만듭니다. 그러나 당신은 대신 숫자를 주었고, 숫자는 컴퓨터의 문자입니다. 그래서 sp.run_numberwas 였을 때 1value가 1있는 문자와 value가있는 문자 2등을 제공했습니다.

이것들은 제어 문자이며 인쇄 가능한 기호가 없으며 터미널에 인쇄하면 다른 결과가 발생합니다. 그래서 그 대신, 그들은 종종 탈출의 다른 종류로 표현하고 있습니다 : \001(진수) \x01(16 진수) ^A값을 갖는 문자에 대한 모든 일반적인 표현이다 1. 값이 0 인 문자는 약간 다르며 C 및 Unix 시스템 호출에서 문자열의 끝을 표시하는 데 사용되는 NUL 바이트입니다.

31보다 높으면 인쇄 가능한 문자가 표시되기 시작합니다 .32는 공백이지만 (보이지 않음) 33 = !, 34 = "등입니다.

그래서,

  • run_ run_^A/ run_^B/— 첫 번째 run_는 0 바이트를 가진 문자열에 해당하며 문자열은 거기서 끝납니다. 다른 사람들은 쉘이 사용하기를 좋아한다는 것을 보여줍니다 ^A. 표기법은 숫자 값이 1 인 문자를로 입력 할 수 있다는 사실을 암시 Ctrl-A합니다.하지만 제어 문자가 아닌 리터럴로 해석하도록 쉘에 지시 Ctrl-V Ctrl-A해야 하지만 적어도 Bash에서는 그렇게해야합니다.

  • 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, \b\tC는 각각 알람 (종), 백 스페이스와 탭의 탈출한다. 그들은 7, 8, 9의 숫자 값을 가지므로 왜 뒤 따르는 지 분명해야합니다 \006. 이러한 C 이스케이프를 사용하는 것은 제어 문자를 표시하는 또 다른 방법입니다. 후행 달러 기호는 줄 끝을 표시합니다.

에 관해서는 cd내 가정이 옳다고 가정 cd run_하면 이상한 후행 문자가없는 단일 디렉토리로 이동 cd run_?해야하며 물음표는 단일 문자와 일치하는 글로브 문자이며 일치하는 파일 이름이 여러 개이므로 오류가 발생해야 cd합니다 하나를 기대합니다.

다음 중 올바른 폴더 표시 옵션은 무엇입니까?

어떤 의미에서 ...

Bash에서는 따옴표 안에 \000\x00이스케이프를 사용하여 $'...'특수 문자를 나타내 $'run_\033거나 (8 진수) $'run_\x1b'문자 값이 27 인 디렉토리 (ESC가 됨)에 해당합니다. (Bash가 10 진수로 이스케이프를 지원한다고 생각하지 않습니다.)

cas의 대답에는 이름을 바꾸는 스크립트가 있으므로 거기에 가지 않겠습니다.


GNU ls인 경우 비 인쇄 문자가 표시되는 방법을 제어하기 위해 -b/ --escape--quoting-style=또는 QUOTING_STYLE환경 변수를 포함한 일부 인용 옵션이 있습니다 . 그래도 문자 버전보다 8 진 탈출을 선호하는 옵션이 있다고 생각하지 않습니다.
Toby Speight

3

실수가 발생한 동일한 환경에서 잘못된 파일 이름과 올바른 파일 이름을 만든 다음 폴더를 올바른 이름으로 이동 / 이름 바꾸기 만하면됩니다.

기존 이름 사이의 충돌을 피하려면 다른 대상 폴더를 사용하는 것이 좋습니다.

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

가능하다면 스크립트를 수정하고 다시 실행하는 것을 선호합니다. 이상한 버그 포스트를 수정하면 비용이 많이 들며 새로운 문제가 발생할 수 있습니다.

행운을 빕니다!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.