많은 파일에 ls를 사용하면 "bash: 인수 목록이 너무 깁니다"라는 오류가 발생합니다.

많은 파일에 ls를 사용하면 "bash: 인수 목록이 너무 깁니다"라는 오류가 발생합니다.

다음을 사용하여 폴더에 있는 .fits 파일의 모든 이름을 채우려고 합니다.

ls *.fits > output_all.txt

폴더의 .fits 파일 수가 >330,000이고 오류 메시지가 나타납니다.

bash: /usr/bin/ls: Argument list too long

이 문제를 어떻게 해결할 수 있나요?

또는 파일을 완전히 생성하지 않아도 됩니다 output_all.txt. 난 그냥 말해야 해죽마이 명령을 사용하여 어떤 .fits 파일을 하나의 큰 .fits 파일로 병합합니까?

stilts tcat in=@output_all.txt out=table_stilts.fits icmd='keepcols "FLUX LOGLAM"'

파일 대신 디렉토리를 입력으로 받아들이도록 STILTS에 지시하는 방법을 알고 있다면 내 문제가 해결될 것입니다 ls. 총질소

답변1

에서 쉘은 ls *.fits로 끝나거나 시작하지 않는 파일 이름을 찾는 모든 어려운 작업을 수행합니다..fits.

그런 다음 해당 목록을 에 전달합니다 ls. 이는 이를 정렬하고(다시 말하지만, 쉘 글롭이 목록을 에 전달하기 전에 정렬했기 때문에 ls) 나중에 표시합니다(구현 및 전송 여부에 따라 열 또는 행당 하나씩). 터미널로) 각 파일이 존재하는지 확인합니다.

따라서 이는 특히 다음을 고려하면 약간 비생산적입니다.

  • --옵션 구분 기호를 잊었 으므로 파일 이름으로 시작하면 -문제가 발생합니다.
  • 옵션 을 잊어버렸기 -d때문에 파일이 디렉터리 유형인 경우 파일 ls자체 대신 해당 내용이 나열됩니다.
  • 셸( 를 포함한 대부분의 셸에서 ) ls과 별도의 명령이므로 결국 시스템 호출을 사용하여 별도의 프로세스에서 실행되어야 하며 결국 인수 및 환경 변수의 누적 크기에 대한 제한을 초과하게 됩니다.bashexecve()

shell 에 의해 생성된 목록을 인쇄해야 하는 경우 대부분의 쉘에 내장된 목록을 *.fits사용할 수 있습니다 printf(따라서 호출되지 않으며 execve()제한 사항이 있음).

printf '%s\n' *.fits > output_all.txt

하지만 이는 다음과 같은 질문을 남깁니다.

일치하는 파일이 없으면 쉘 *.fits에 그대로 남아 있으므로 결국 인쇄 됩니다 .bash*.fitsprintf*.fits<newline>

ls존재하지 않는 *.fits파일에 대한 오류 메시지를 표시하고 비워 둡니다 output_all.txt.

nullglob이는 옵션(bash에서 bash 복사 zsh)을 통해 변경할 수 있으며, 이로 인해 *.fits확장이 비어 있게 됩니다. 그러나 또 다른 문제에 직면하게 됩니다. 형식을 제외하고 매개변수가 전달되지 않으면 printf빈 매개변수가 전달된 것처럼 형식이 여전히 한 번 탐색되므로 output_all.txt.

이 문제는 다음을 통해 해결될 수 있습니다.

shopt -s nullglob
println() {
  [ "$#" -eq 0 ] || printf '%s\n' "$@"
}
println *.fits > output_all.txt

zsh대신 다음 으로 전환하면 bash더 쉬울 것입니다 .

print -rC1 -- *.fits(N) > output_all.txt

여기서 glob을 N활성화 하고 해당 인수 aw를 nullglobolumn에 인쇄합니다 . 여기서 중요한 점은 인수가 전달되지 않으면 아무것도 인쇄되지 않는다는 것입니다.print -rC1r1 C

를 사용하면 zshglob 한정자(예:)를 사용하여 일반 파일(디렉토리, 심볼릭 링크, fifos... 제외)로만 목록을 제한하거나 ()를 사용하여 숨겨진 파일을 포함할 수도 있습니다....*.fits(N.)D*.fits(ND.)


마지막으로 파일 찾기를 언제든지 미룰 수 있지만 find목록을 정렬하고 숨겨진 파일을 제외하고 접두사를 피해야 하는 경우 ./이 작업도 빨리 지루해지고 GNU 확장이 필요합니다. 예를 들어 다음과 같습니다 print -rC1 -- *.fits(N.).

LC_ALL=C find . -maxdepth 1 ! -name '.*' -type f -printf '%P\0' |
  sort -z | tr '\0' '\n' > output_all.txt

답변2

단일 명령줄에 허용되는 문자 수에는 제한이 있습니다. 최신 Linux 시스템에서는 약 2백만 자입니다. 이는 다른 시스템에 따라 다를 수 있습니다.

현재 디렉터리에 있는 *.fits 파일의 파일 이름이 단일 명령줄에 맞지 않는 것 같습니다. 이 문제를 해결하는 방법은 여러 가지가 있으며, 가장 쉬운 방법 중 하나는 find대체 방법을 사용하는 것입니다. 예를 들어

find . -maxdepth 1 -type f -name '*.fits' > output_all.txt

또 다른 옵션은 .e.g.를 사용하는 것입니다 perl.

perl -e 'print map { "$_\n" if -f $_ } sort glob "*.fits"' > output_all.txt

또는:

perl -E 'foreach $f (sort glob "*.fits") { say $f if -f $f }' > output_all.txt

심지어:

perl -E 'foreach $f (sort grep { -f } glob "*.fits") { say $f }' > output_all.txt

(Perl에서는 이를 수행하는 방법이 많이 있습니다.)

참고: find버전~ 할 것이다.현재 디렉터리에 숨겨진 파일 이름(즉, 로 시작하는 파일 이름)이 있으면 나열합니다 . 펄 버전에 익숙해. 두 버전 모두 인쇄만 가능합니다.일반 파일.fits디렉토리, 심볼릭 링크, 명명된 파이프, 소켓 또는 장치 노드가 아닌 로 끝납니다 . 출력은 find정렬되지 않고 파일 이름은 디렉토리에 있는 순서대로 인쇄됩니다. Perl 버전은 정렬됩니다(오름차순 알파 정렬. 그런데 Perl의 내장 정렬 기능은 파일 크기나 타임스탬프를 포함한 다양한 기준에 따라 정렬할 수 있을 만큼 유연합니다).

그건 그렇고, Perl에는파일::찾기라이브러리 모듈은 findcan과 같은 재귀 검색을 수행할 수 있지만 검색된 파일 이름을 필터링, 정렬 및 조작한 다음 해당 파일을 처리할 수 있는 Perl의 모든 기능을 사용할 수 있습니다. File::FindPerl에 포함된 핵심 라이브러리입니다. 특정 디렉토리의 파일만 검색해야 한다면 Perl의 glob()기능으로 충분합니다.


stiltsAFAICT 게시한 링크를 보면 죽마에 대한 인수가 in=@filenameNUL로 구분된 입력을 처리할 수 없는 것으로 나타납니다. 따라서 파일 이름에 줄 바꿈이 포함된 .fits 파일이 있는 경우 해당 파일의 이름을 바꿔야 합니다.

만약에stilts 할 수 있다NUL로 구분된 파일 이름 목록을 처리하려면 find의 옵션을 사용하거나 Perl 스크립트에서 로 변경하여 -print0NUL로 구분된 목록을 생성할 수 있습니다. 이는 아무 관련이 없을 수도 있지만 NUL을 구분 기호로 처리할 수 있는 다른 프로그램에서 동일한 문제가 있는지 아는 것이 유용합니다(많은 프로그램에 , 및/또는 옵션이 있음).\n\0stilts-z-Z-0

find . -maxdepth 1 -type f -name '*.fits' -print0 > output_all.nul

또는

perl -e 'print map { "$_\0" if -f "$_" } sort glob "*.fits"' > output_all.nul

관련 정보