왜 ‘ls’를 파싱하지 않는가 (그리고 대신 무엇을해야 하는가)? 사람들이 나에게 할 수 없다고 계속 말하고

나는 이 링크 를 인용하여 “파싱하지 마라 ls!” 이것은 몇 가지 이유로 나를 귀찮게합니다.

  1. 그 링크의 정보는 약간의 질문으로 도매로 받아 들여졌지만 캐주얼 독서에서 최소한 몇 가지 오류를 선택할 수는 있습니다.

  2. 또한 그 링크에 명시된 문제가 해결책을 찾고자하는 욕구를 불러 일으키지 않은 것처럼 보입니다.

첫 번째 단락에서 :

[ls]파일 목록 을 요청할 때 큰 문제가 있습니다. 유닉스는 공백 문자, 줄 바꿈, 쉼표, 파이프 기호 및 거의 모든 다른 문자를 포함하여 파일 이름에 거의 모든 문자를 허용합니다. NUL을 제외한 분리 문자. … ls파일 이름을 줄 바꿈으로 구분합니다. 이름에 줄 바꿈이있는 파일이 생길 때까지 괜찮습니다. 그리고 줄 ls바꿈 대신 NUL 문자로 파일 이름을 종료 할 수 있는 구현 방법을 모르므로으로 파일 이름 목록을 안전하게 가져올 수 없습니다 ls.

버머 맞지? 어떻게 지금까지 우리는 개행 문자가 개행 문자를 포함 할 수있는 데이터에 대한 상장 데이터 집합을 종결 처리 할 수 있습니까? 글쎄,이 웹 사이트에서 질문에 대답하는 사람들이 매일 이런 종류의 일을하지 않았다면, 우리가 어려움을 겪고 있다고 생각할 수 있습니다.

사실 대부분의 ls구현은 실제로 출력을 구문 분석하기 위해 매우 간단한 API를 제공하며 우리는 그것을 실현하지 않고도 모든 작업을 수행했습니다. 파일 이름을 null로 끝낼 수있을뿐만 아니라 null을 사용하거나 원하는 다른 임의의 문자열로 파일 이름을 시작할 수 있습니다. 또한 파일 유형별로 이러한 임의의 문자열을 할당 할 수 있습니다 . 고려하십시오 :

LS_COLORS='lc=\0:rc=:ec=\0\0\0:fi=:di=:' ls -l --color=always | cat -A
total 4$
drwxr-xr-x 1 mikeserv mikeserv 0 Jul 10 01:05 ^@^@^@^@dir^@^@^@/$
-rw-r--r-- 1 mikeserv mikeserv 4 Jul 10 02:18 ^@file1^@^@^@$
-rw-r--r-- 1 mikeserv mikeserv 0 Jul 10 01:08 ^@file2^@^@^@$
-rw-r--r-- 1 mikeserv mikeserv 0 Jul 10 02:27 ^@new$
line$
file^@^@^@$
^@

자세한 내용은 이것을 참조하십시오 .

이제이 기사의 다음 부분은 실제로 나를 이해시켜줍니다.

$ ls -l
total 8
-rw-r-----  1 lhunath  lhunath  19 Mar 27 10:47 a
-rw-r-----  1 lhunath  lhunath   0 Mar 27 10:47 a?newline
-rw-r-----  1 lhunath  lhunath   0 Mar 27 10:47 a space

문제는의 출력에서 ls사용자 또는 컴퓨터가 파일 이름을 구성하는 부분을 말할 수 없다는 것 입니다. 각 단어입니까? 아니요. 각 줄입니까? 아닙니다.이 질문에 대한 정답은 없습니다 : 당신은 말할 수 없습니다.

또한 ls파일 이름 데이터를 때때로 깨뜨리는 방법에 주목 하십시오 (이 경우 “a”
“newline”\n 사이의 문자를 ? 물음표 로 바꿨습니다 . …

현재 디렉토리의 모든 파일을 반복하려면 for루프와 glob를 사용하십시오.

for f in *; do
    [[ -e $f ]] || continue
    ...
done

저자는이 호출 파일 이름을 잘못 전달 되면 ls쉘 globs와를 포함하는 파일 이름의 목록을 반환 한 후와 파일 목록을 검색 쉘 글로브를 사용하는 것이 좋습니다!

다음을 고려하세요:

printf 'touch ./"%b"\n' "file\nname" "f i l e n a m e" |
    . /dev/stdin
ls -1q

f i l e n a m e
file?name

IFS="
" ; printf "'%s'\n" $(ls -1q)

'f i l e n a m e'
'file
name'

POSIX는 피연산자를 다음 -1과 같이 정의 합니다 -q ls.

-q-인쇄 할 수없는 파일 이름 문자 및 <tab>s의 각 인스턴스를 물음표 ( '?') 문자로 작성하십시오. 출력이 터미널 장치에 대한 경우 구현시 기본적으로이 옵션을 제공 할 수 있습니다.

-1(숫자 1) 출력이 한 줄에 하나씩 입력되도록합니다.

글 로빙에는 고유 한 문제가 없습니다. 어떤 문자 ? 일치 하므로 ?목록에서 여러 개의 일치하는 결과가 동일한 파일과 여러 번 일치합니다. 그것은 쉽게 처리됩니다.

이 작업을 수행하는 방법이 요점은 아니지만 결국에는 많은 시간이 걸리지 않으며 아래에 설명되어 있습니다 . 이유 에 관심이있었습니다 . 내가 생각할 때, 그 질문에 대한 가장 좋은 대답이 받아 들여졌습니다. 사람들이 할 수없는 것보다 할 있는 일을 사람들에게 알리는 데 더 자주 집중하는 것이 좋습니다 . 내가 생각 하듯이 적어도 당신은 틀린 것으로 증명 될 가능성이 훨씬 낮습니다.

그러나 왜 시도조차합니까? 분명히, 나의 주된 동기는 다른 사람들이 나에게 할 수 없다고 계속 말하고 있다는 것이었다. 나는 ls당신이 무엇을 찾아야 하는지를 알기 만하면 출력이 규칙적이고 예측 가능하다는 것을 잘 알고 있습니다. 잘못된 정보는 대부분의 일보다 나를 귀찮게합니다.

그러나 Patrick과 Wumpus Q. Wumbley의 답변 (후자의 멋진 핸들에도 불구하고)을 제외하고는 사실을 제외 하고는 대답 대부분의 정보가 대부분 올바른 것으로 간주합니다. 일반적으로 구문 분석하는 것보다 현재 디렉토리를 검색 할 때 더 효과적 ls입니다. 그들은 내 점에서 적어도 충분한 이유 중 하나는 위의 기사에서 인용 한 잘못된 정보를 전파하거나 그들이 수용 할 명분 있습니다 정당화하기 위해, 그러나 아니다 ” 구문 분석되지 않습니다 ls.

Patrick의 답변의 일관되지 않은 결과는 주로 zshthen을 사용한 결과입니다 bash. zsh-기본적으로- 이식 가능한 방식으로 $(대체 단어를 단어 분리하지 않습니다 ). 그래서 그가 나머지 파일들은 어디로 갔냐 고 물었을 때 ? 그 질문에 대한 대답은 당신의 껍질이 그들을 먹었다는 것입니다. 휴대용 쉘 코드를 SH_WORD_SPLIT사용 zsh하고 처리 할 때 변수 를 설정해야하는 이유가 여기에 있습니다. 나는 그의 답변에서 이것을 지적하지 못한 것이 끔찍한 오도라고 생각합니다.

Wumpus의 대답은 나를 위해 계산되지 않습니다. 목록 컨텍스트에서 ?캐릭터 쉘 글로브입니다. 다른 말을하는 방법을 모르겠습니다.

여러 결과 사례를 처리하려면 글로브의 욕심을 제한해야합니다. 다음은 끔찍한 파일 이름의 테스트 기반을 만들고 표시합니다.

{ printf %b $(printf \\%04o `seq 0 127`) |
sed "/[^[-b]*/s///g
        s/\(.\)\(.\)/touch '?\v\2' '\1\t\2' '\1\n\2'\n/g" |
. /dev/stdin

echo '`ls` ?QUOTED `-m` COMMA,SEP'
ls -qm
echo ; echo 'NOW LITERAL - COMMA,SEP'
ls -m | cat
( set -- * ; printf "\nFILE COUNT: %s\n" $# )
}

산출

`ls` ?QUOTED `-m` COMMA,SEP
??\, ??^, ??`, ??b, [?\, [?\, ]?^, ]?^, _?`, _?`, a?b, a?b

NOW LITERAL - COMMA,SEP
?
 \, ?
     ^, ?
         `, ?
             b, [       \, [
\, ]    ^, ]
^, _    `, _
`, a    b, a
b

FILE COUNT: 12

지금 나는거야 안전한 아닌 모든 문자 /slash, -dash, :colon다음 쉘 글로브에서, 또는 알파 – 숫자 문자 sort -u의 고유 결과에 대한 목록입니다. ls인쇄 할 수없는 문자는 이미 보호 되었으므로 안전합니다. 손목 시계:

for f in $(
        ls -1q |
        sed 's|[^-:/[:alnum:]]|[!-\\:[:alnum:]]|g' |
        sort -u | {
                echo 'PRE-GLOB:' >&2
                tee /dev/fd/2
                printf '\nPOST-GLOB:\n' >&2
        }
) ; do
        printf "FILE #$((i=i+1)): '%s'\n" "$f"
done

산출:

PRE-GLOB:
[!-\:[:alnum:]][!-\:[:alnum:]][!-\:[:alnum:]]
[!-\:[:alnum:]][!-\:[:alnum:]]b
a[!-\:[:alnum:]]b

POST-GLOB:
FILE #1: '?
           \'
FILE #2: '?
           ^'
FILE #3: '?
           `'
FILE #4: '[     \'
FILE #5: '[
\'
FILE #6: ']     ^'
FILE #7: ']
^'
FILE #8: '_     `'
FILE #9: '_
`'
FILE #10: '?
            b'
FILE #11: 'a    b'
FILE #12: 'a
b'

아래에서 문제에 다시 접근하지만 다른 방법론을 사용합니다. \0null 이외 의 /ASCII 문자는 경로명에서 금지 된 유일한 바이트입니다. 여기에 globs를두고 대신 POSIX 지정 -d옵션 ls과 POSIX 지정 -exec $cmd {} +구성을 결합 find합니다. 때문에 find오직 자연스럽게 방출합니다 /순서를은 쉽게 다음은 각 항목에 대한 모든 dentry 정보를 포함 재귀 안정적으로 구분 된 파일 목록을 조달. 다음과 같이 무엇을 할 수 있는지 상상해보십시오.

#v#note: to do this fully portably substitute an actual newline \#v#
#v#for 'n' for the first sed invocation#v#
cd ..
find ././ -exec ls -1ldin {} + |
sed -e '\| *\./\./|{s||\n.///|;i///' -e \} |
sed 'N;s|\(\n\)///|///\1|;$s|$|///|;P;D'

###OUTPUT

152398 drwxr-xr-x 1 1000 1000        72 Jun 24 14:49
.///testls///

152399 -rw-r--r-- 1 1000 1000         0 Jun 24 14:49
.///testls/?
            \///

152402 -rw-r--r-- 1 1000 1000         0 Jun 24 14:49
.///testls/?
            ^///

152405 -rw-r--r-- 1 1000 1000         0 Jun 24 14:49
.///testls/?
        `///
...

ls -i 특히 결과 고유성이 문제가 될 때 매우 유용 할 수 있습니다.

ls -1iq |
sed '/ .*/s///;s/^/-inum /;$!s/$/ -o /' |
tr -d '\n' |
xargs find

이것들은 내가 생각할 수있는 가장 휴대용 수단입니다. GNU ls를 사용하면 다음을 수행 할 수 있습니다.

ls --quoting-style=WORD

마지막으로, inode 번호가 필요할 때 자주 사용 하는 훨씬 간단한 구문 분석ls 방법이 있습니다.

ls -1iq | grep -o '^ *[0-9]*'

그것은 단지 inode 번호를 반환합니다-이것은 또 다른 편리한 POSIX 지정 옵션입니다.



답변

나는 이것에 대해 전혀 확신하지는 못하지만 , 충분한 노력을 기울일 준비가되어 있다면 , “적대적”의 얼굴 앞에서조차도 믿을만한 결과를 파싱 할 있다는 주장을 가정 해 보자. ls작성한 코드를 알고 있으며 의도적으로 파일 이름을 변경하도록 설계된 파일 이름을 선택하고 있습니다.

그렇게 할 수 있더라도 여전히 나쁜 생각 입니다.

Bourne 쉘은 좋은 언어가 아닙니다. 다른 요소 (예 :)보다 극단적 인 이식성이 더 중요하지 않으면 복잡한 것에 사용하면 안됩니다 autoconf.

나는 당신이 출력을 파싱하는 ls것이 쉘 스크립트에 대한 최소한의 저항 경로처럼 보이는 문제에 직면한다면 , 그것은 당신이하는 일이 쉘에 대해 너무 복잡 하고 전체를 다시 작성해야한다는 강력한 표시라고 주장 한다 펄 또는 파이썬. 다음은 Python의 마지막 프로그램입니다.

import os, sys
for subdir, dirs, files in os.walk("."):
    for f in dirs + files:
      ino = os.lstat(os.path.join(subdir, f)).st_ino
      sys.stdout.write("%d %s %s\n" % (ino, subdir, f))

파일 이름에 특이한 문자가 있으면 문제가 없습니다. 출력 이 모호한 것과 같은 방식으로 출력 ls이 모호하지만 “실제”프로그램에서는 중요하지 않습니다 (이와 같은 데모와는 달리). os.path.join(subdir, f)직접 결과를 사용하십시오 .

똑같이 중요하고, 작성한 내용과 완전히 대조적으로, 6 개월 후에도 여전히 의미가 있으며 약간 다른 것을 수행해야 할 때 쉽게 수정할 수 있습니다. 예를 들어, 도트 파일 및 편집기 백업을 제외하고 기본 이름별로 알파벳 순서로 모든 것을 처리해야한다고 가정하십시오.

import os, sys
filelist = []
for subdir, dirs, files in os.walk("."):
    for f in dirs + files:
        if f[0] == '.' or f[-1] == '~': continue
        lstat = os.lstat(os.path.join(subdir, f))
        filelist.append((f, subdir, lstat.st_ino))

filelist.sort(key = lambda x: x[0])
for f, subdir, ino in filelist:
   sys.stdout.write("%d %s %s\n" % (ino, subdir, f))


답변

정보가 완전히 정확하기 때문에 그 링크는 많은 참조를했으며 매우 오랫동안 사용되었습니다.


ls인쇄 할 수없는 문자를 glob 문자 yes로 대체하지만 해당 문자는 실제 파일 이름에 없습니다. 이것이 왜 중요한가? 두 가지 이유 :

  1. 해당 파일 이름을 프로그램에 전달하면 해당 파일 이름이 실제로 존재하지 않습니다. 실제 파일 이름을 얻으려면 glob를 확장해야합니다.
  2. 파일 glob이 둘 이상의 파일과 일치 할 수 있습니다.

예를 들면 다음과 같습니다.

$ touch a$'\t'b
$ touch a$'\n'b
$ ls -1
a?b
a?b

정확히 같은 두 개의 파일이 어떻게 있는지 주목하십시오. 둘 다 다음과 같이 표현되면 어떻게 구별 a?b합니까?


ls가 쉘 글로브가 포함 된 파일 이름 목록을 반환 한 다음 쉘 글로브를 사용하여 파일 목록을 검색하는 것이 좋습니다.

여기에 차이점이 있습니다. 표시된대로 글로브를 다시 받으면 해당 글로브가 둘 이상의 파일과 일치 할 수 있습니다. 그러나 glob와 일치하는 결과를 반복하면 glob가 아닌 정확한 파일이 다시 나타납니다.

예를 들면 다음과 같습니다.

$ for file in *; do printf '%s' "$file" | xxd; done
0000000: 6109 62                                  a.b
0000000: 610a 62                                  a.b

어떻게 주목 xxd출력을 보여줍니다 $file원시 문자를 포함 \t하고 \n있지를 ?.

를 사용 ls하면 대신이를 얻습니다.

for file in $(ls -1q); do printf '%s' "$file" | xxd; done
0000000: 613f 62                                  a?b
0000000: 613f 62                                  a?b

“나는 사용하지 왜, 어쨌든 반복하는거야 ls?”

당신의 예는 실제로 효과가 없습니다. 작동하는 것처럼 보이지만 작동하지 않습니다.

나는 이것을 언급하고있다 :

 for f in $(ls -1q | tr " " "?") ; do [ -f "$f" ] && echo "./$f" ; done

파일 이름이 많은 디렉토리를 만들었습니다.

$ for file in *; do printf '%s' "$file" | xxd; done
0000000: 6120 62                                  a b
0000000: 6120 2062                                a  b
0000000: 61e2 8082 62                             a...b
0000000: 61e2 8083 62                             a...b
0000000: 6109 62                                  a.b
0000000: 610a 62                                  a.b

코드를 실행하면 다음과 같은 결과가 나타납니다.

$ for f in $(ls -1q | tr " " "?") ; do [ -f "$f" ] && echo "./$f" ; done
./ab
./ab

나머지 파일은 어디로 갔습니까?

대신 시도해 보자.

$ for f in $(ls -1q | tr " " "?") ; do stat --format='%n' "./$f"; done
stat: cannot stat ‘./a?b’: No such file or directory
stat: cannot stat ‘./a??b’: No such file or directory
./ab
./ab
stat: cannot stat ‘./a?b’: No such file or directory
stat: cannot stat ‘./a?b’: No such file or directory

이제 실제 glob을 사용하십시오 :

$ for f in *; do stat --format='%n' "./$f"; done
./a b
./a  b
./ab
./ab
./a b
./a
b

bash로

위 예제는 일반적인 쉘 zsh와 함께 사용되었습니다. bash로 절차를 반복하면 예제와 완전히 다른 결과 집합이 나타납니다.

동일한 파일 세트 :

$ for file in *; do printf '%s' "$file" | xxd; done
0000000: 6120 62                                  a b
0000000: 6120 2062                                a  b
0000000: 61e2 8082 62                             a...b
0000000: 61e2 8083 62                             a...b
0000000: 6109 62                                  a.b
0000000: 610a 62                                  a.b

코드와 근본적으로 다른 결과 :

for f in $(ls -1q | tr " " "?") ; do stat --format='%n' "./$f"; done
./a b
./ab
./ab
./a b
./a
b
./a  b
./ab
./ab
./a b
./ab
./ab
./a b
./a
b
./a b
./ab
./ab
./a b
./a
b

쉘 글로브를 사용하면 완벽하게 작동합니다.

$ for f in *; do stat --format='%n' "./$f"; done
./a b
./a  b
./ab
./ab
./a b
./a
b

bash가 이런 식으로 동작하는 이유는 대답의 시작 부분에서 “파일 글로브가 둘 이상의 파일과 일치 할 수 있습니다”라는 점으로 되돌아갑니다.

lsa?b여러 파일에 대해 동일한 glob ( )을 반환하므로이 glob 를 확장 할 때마다 일치하는 모든 단일 파일을 얻습니다.


내가 사용하고있는 파일 목록을 다시 만드는 방법 :

touch 'a b' 'a  b' a$'\xe2\x80\x82'b a$'\xe2\x80\x83'b a$'\t'b a$'\n'b

16 진 코드는 UTF-8 NBSP 문자입니다.


답변

조금 시도해 보자.

$ touch a$'\n'b a$'\t'b 'a b'
$ ls
a b  a?b  a?b
$ IFS="
"
$ set -- $(ls -1q | uniq)
$ echo "Total files in shell array: $#"
Total files in shell array: 4

보다? 그것은 이미 잘못되었습니다. 3 개의 파일이 있지만 bash는 4를보고합니다. 이는에 의해 전달되기 전에 쉘에 의해 set생성 된 glob이 제공 되기 때문 입니다. 당신이 얻는 이유입니다 :lsset

$ for x ; do
>     printf 'File #%d: %s\n' $((i=$i+1)) "$x"
> done
File #1: a b
File #2: a b
File #3: a    b
File #4: a
b

또는 원하는 경우 :

$ printf ./%s\\0 "$@" |
> od -A n -c -w1 |
> sed -n '/ \{1,3\}/s///;H
> /\\0/{g;s///;s/\n//gp;s/.*//;h}'
./a b
./a b
./a\tb
./a\nb

위의에 실행되었습니다 bash 4.2.45.


답변

출력 ls -q은 전혀 문제가되지 않습니다. ?“직접 표시 할 수없는 문자가 있습니다”라는 의미로 사용 됩니다. 글롭 ?은 “모든 문자가 허용됩니다”라는 의미로 사용 됩니다.

globs와는 다른 특수 문자가 ( *[]이상을, 그리고 내부 []쌍 더있다). 그들 중 누구도에 의해 탈출하지 않습니다 ls -q.

$ touch x '[x]'
$ ls -1q
[x]
x

ls -1q출력 을 처리하면 glob 세트가 있고 확장되어 x두 번 얻을뿐만 아니라 [x]완전히 놓칠 수 있습니다. 글로브로서, 문자열 자체와 일치하지 않습니다.

ls -q 셸에 피드백을 줄 수있는 물건을 만들지 말고 미친 캐릭터로부터 눈이나 터미널을 보호하기위한 것입니다.


답변

대답은 간단합니다. 특별한 경우는 ls처리 할 수있는 이점보다 중요합니다. ls출력을 구문 분석하지 않으면 이러한 특별한 경우를 피할 수 있습니다 .

여기서 만트라 는 사용자 파일 시스템절대 신뢰하지 않습니다 (사용자 입력절대 신뢰하지 않음 ). 100 % 확실하게 항상 작동하는 방법이 있다면 ls, 동일하지만 덜 확실 하더라도 선호하는 방법이어야합니다 . terdonPatrick이 광범위하게 다루었 으므로 기술적 세부 사항에 대해서는 다루지 않겠습니다 . 나는 ls직업 / 명예가있는 중요한 (그리고 아마도 비싼) 거래에서 사용하는 위험 때문에 피할 수 있다면 불확실성이없는 솔루션을 선호 할 것임을 알고 있습니다.

어떤 사람들은 확실성보다 위험을 선호 하지만 , 버그 보고서를 제출했습니다 .


답변

사람들이 절대로 무언가를하지 않는다고 말하는 이유 는 반드시 긍정적으로 올바르게 할 수 없기 때문에 반드시 그런 것은 아닙니다. 우리는 그렇게 할 수는 있지만, 공간적으로나 시간적으로 더 복잡하고 덜 효율적일 수 있습니다. 예를 들어 “x86 어셈블리에 큰 전자 상거래 백엔드를 구축하지 마십시오”라고 말하는 것이 좋습니다.

이제 당면한 문제에 대해 설명했습니다. 시연했듯이 ls를 구문 분석하고 올바른 결과를 제공하는 솔루션을 만들 수 있으므로 정확성은 문제가되지 않습니다.

더 복잡합니까? 예, 그러나 도우미 기능 뒤에 숨길 수 있습니다.

이제 효율성으로

공간 효율성 : 솔루션은 uniq중복을 필터링하는 데 의존 하므로 결과를 느리게 생성 할 수 없습니다. 따라서 O(1)vs. O(n)또는 둘 다 O(n).

시간 효율성 : 모범 사례는 uniq그래서 우리는 여전히이 해시 맵 방식을 사용 O(n)요소의 수에 알고리즘 조달을 그건 아마 불구하고 O(n log n).

이제 진짜 문제 : 알고리즘이 여전히 나빠 보이지 않지만 n에 대한 요소가 아닌 조달 된 요소를 사용하는 것이 정말 조심 스럽습니다 . 그것이 큰 차이를 만들어 내기 때문입니다. \n\nglob을 생성 하는 파일이 있다고 가정하면 ??목록의 2 개 문자 파일마다 일치합니다. 재미있게도 다른 파일 \n\r이 있으면 결과적으로 ??2 개의 문자 파일도 모두 반환합니다. 선형 행동 대신 지수는 확실히 “런타임 행동 악화”로 규정됩니다. 이는 실제 알고리즘과 이론적 CS 저널에 논문을 작성하는 것의 차이점입니다.

모두가 모범을 좋아합니까? 여기 있습니다 “test”라는 폴더를 만들고 폴더가있는 동일한 디렉토리에서이 python 스크립트를 사용하십시오.

#!/usr/bin/env python3
import itertools
dir = "test/"
filename_length = 3
options = "\a\b\t\n\v\f\r"

for filename in itertools.product(options, repeat=filename_length):
        open(dir + ''.join(filename), "a").close()

이 작업 만하는 것은 길이가 7자인 모든 제품을 생성하는 것입니다. 고등학교 수학은 343 개의 파일이어야한다고 말합니다. 인쇄가 정말 빨라야합니다.

time for f in *; do stat --format='%n' "./$f" >/dev/null; done
real    0m0.508s
user    0m0.051s
sys 0m0.480s

이제는 이것을 얻을 수 없기 때문에 첫 번째 해결책을 시도해 봅시다.

eval set -- $(ls -1qrR ././ | tr ' ' '?' |
sed -e '\|^\(\.\{,1\}\)/\.\(/.*\):|{' -e \
        's//\1\2/;\|/$|!s|.*|&/|;h;s/.*//;b}' -e \
        '/..*/!d;G;s/\(.*\)\n\(.*\)/\2\1/' -e \
        "s/'/'\\\''/g;s/.*/'&'/;s/?/'[\"?\$IFS\"]'/g" |
uniq)

리눅스 민트 16에서 작동하는 것 (이 방법의 유용성에 대해 볼륨을 말한다고 생각합니다).

어쨌든 위의 결과는 결과를 얻은 후에 만 ​​결과를 필터링하기 때문에 이전 솔루션은 적어도 후자만큼 빠르지 않아야합니다 (그중 inode 트릭은 없지만 신뢰할 수 없으므로 정확성을 포기합니다).

그래서 지금 얼마나 오래

time for f in $(ls -1q | tr " " "?") ; do stat --format='%n' "./$f" >/dev/null; done

갖다? 글쎄, 나는 정말로 모른다, 343 ^ 343 파일 이름을 확인하는 데 시간이 걸린다-나는 우주의 열사병 후에 당신에게 말할 것이다.


답변

OP의 진술 의도

서문 및 원본 답변의 근거 2015 년 5 월 18 일에 업데이트 됨

: mikeserv (영업 이익)는 자신의 질문에 대한 최신 업데이트에 명시된 내가 않는다 ” 수치를 고려 그게 내가 처음 불구하고 잘못된 정보의 소스를 지적이 질문을, 불행하게도, 여기에 가장 upvoted 대답은 상당 부분 오해의 소지가합니다. “

글쎄요. 나는 내가 찾을 단지 내 의미를 설명하는 방법을 알아 내려고 너무 많은 시간을 소비하는 것이 아니라 수치이었다 느끼는 것을 내가 같은 질문을 다시 읽어보십시오. 이 질문은 “오히려 답변보다는 [생성] 토론을”결국 과에 무게 결국 텍스트의 ~ 18K 심지어 블로그 게시물에 대한 긴 될 것이다 (단지 명확하게하기 위해, 혼자 질문에 대한).

그러나 StackExchange는 비누 상자가 아니며 블로그가 아닙니다. 그러나 실제로는 적어도 둘 다로 사용했습니다. 사람들은 사람들의 실제 질문에 대답하는 대신 “To-Point-Out”에 많은 시간을 소비했습니다. 이 시점에서 OP는 질문이 전혀 의도 된 것이 아니라고 명시 적으로 언급 했으므로 질문을 우리 형식에 적합하지 않은 것으로 플래그 지정합니다.

이 시점에서 나는 나의 대답이 요점인지 아닌지 확신하지 못한다. 아마 그렇지는 않지만 귀하의 질문 중 일부에 관한 것일 수도 있으며 다른 사람에게 유용한 답변 일 수도 있습니다. 초보자는 마음을 사로 잡습니다. 그 중 일부는 “경험이 없으면” “때때로”로 바뀝니다. 🙂

일반적으로 …

남은 거친 가장자리를 용서하십시오. 나는 이미 이것에 너무 많은 시간을 보냈다 … OP를 직접 인용하지 않고 (원래 의도 한대로) 요약하고 말을 표현하려고합니다.

[원래 답변에서 크게 재 작업]
고려할 때 OP가 내가 대답 한 질문에 대해 강조하고 있다는 강조를 잘못 읽었다 고 생각합니다. 그러나 언급 된 요점 제기되었으며, 나는 그들이 요점이라고 생각하고 초보자에게 조언과 관련하여 다른 맥락에서 제기 된 문제를 해결하기 위해 대답을 크게 그대로 두었습니다.

원래 게시물은 여러 가지 방법으로 여러 기사에서« ls출력을 구문 분석하지 마십시오 »또는« ls출력을 구문 분석해서는 안됩니다» 등과 같은 조언을 제공 한 이유를 물었습니다 .

이 문제에 대한 나의 제안 된 해결책은 이런 종류의 진술의 사례는 단지 약간 다른 방식으로 표현 된 관용구의 예일 뿐이며, 절대 정량자가 명령형 [예 :«하지 말아야 할 X», «[당신은 항상 Y해야한다],«[하나는 절대 Z 야하지 않아야한다»], 특히 절대적인 진실로 의도 된 것이 아니라, 주제에 새로운 사람들에게 주어질 때 일반적인 규칙이나 지침으로 사용되는 진술을 그럼에도 불구하고 그러한 진술의 명백한 형태 .

새로운 주제를 배우기 시작할 때, 왜 다른 방법으로해야하는지에 대해 잘 이해하지 않는 한, 경험이 많은 사람의 지시가없는 한 예외없이 허용 된 일반 규칙을 따르는 것이 좋습니다. 그 자신. 기술과 경험이 높아짐에 따라 특정 상황에서 규칙이 적용되는시기와 여부를 더 결정할 수 있습니다. 일단 당신이 상당한 수준의 경험에 도달하면, 당신은 우선 일반 규칙의 이유를 이해할 것입니다. 그리고 그 시점에서 당신은 규칙의 이유가 어떤 레벨에 적용되는지에 대한 판단을 사용할 수 있습니다. 그 상황, 그리고 우선적으로 우려되는 사항이 있는지에 관한 것입니다.

그리고 아마도 전문가가 아마도 “규칙”을 위반하는 일을 할 수도 있습니다. 그러나 그렇게함으로써 “규칙”이 줄어들지는 않습니다.

그리고, 당면한 주제 : 내 견해로는, 전문가가이 규칙을 완전히 위반하지 않고이 규칙을 위반할 수 있기 때문에 초보자에게 “때때로” 구문 분석 괜찮 ls: 때문에, 출력 이 아니다 . 또는 적어도 초보자가 그렇게하는 것은 옳지 않습니다.

항상 폰을 중앙에 놓으십시오. 개구부에서 한 번의 움직임으로; 가장 빠른 기회의 성; 감독 이전의 기사; 림의 기사는 잔인하다. 항상 계산을 끝까지 볼 수 있는지 확인하십시오! (후회, 미안, 피곤해, 그것은 체스 StackExchange를위한 것입니다.)

규칙, 깨질 것인가?

초보자를 대상으로하거나 초보자가 읽을 수있는 주제에 대한 기사를 읽을 때 종종 다음과 같은 내용이 표시됩니다.

  • ” X를 절대로 하지 말아야합니다. “
  • “절대로 Q!”
  • “Z를하지 마십시오.”
  • “언제나 Y를해야한다!”
  • “무엇이든 C.”

이러한 진술은 확실히 절대적이고 영원한 규칙을 나타내는 것처럼 보이지만, 그렇지 않습니다. 대신에 이것은이 규칙을 읽는 초보자를 위해 적어도 하나의 적절한 방법 인 적어도 하나의 적절한 방법 인 일반적인 규칙 (일명 “지침”, “엄지 규칙”, “기본 사항”등)을 나타내는 방법입니다. 그러나이 규칙이 절대적인 것으로 명시되어 있기 때문에 규칙은 분명히 반복되는 문제를 다룰 때 얻은 지식을 기록하고 전달하는 방법으로 전문가와 전문가를 우선적으로 구속하지 않습니다. 그들의 특정 기술에 문제.]

이러한 규칙은 전문가가 복잡하거나 미묘한 문제를 어떻게 처리 할 것인지를 밝히지 않을 것입니다. 또는 처음에 규칙으로 이끈 우려는 단순히 적용되지 않습니다. 전문가들은 특정 상황에서 이해가되지 않는 규칙을 어기는 것을 두려워하지 않습니다 (또는 두려워해서는 안됩니다!). 전문가들은 지속적으로 자신의 기술에 대한 다양한 위험과 우려의 균형을 다루고 있으며 이러한 규칙을 어 기고 다양한 요소의 균형을 유지하고 따라야 할 규칙에 의존 할 수없는 판단을 자주 사용해야합니다. 가지고 Goto예를 들어 : 그들이 유해 여부에 긴, 반복, 논쟁이있었습니다. (네,하지 않습니다 gotos를 사용합니다. D)

모달 건의안

적어도 영어로 된 이상한 특징은 다른 많은 언어에서 일반적인 규칙으로 상상할 수 있다는 것입니다. 상황이 적절할 때 규칙을 어길 것이라는 것을 알고 있습니다. 따라서 이러한 진술은 모달 로직의 동일한 진술과 동일하지 않습니다.

이것이 바로 그들이 관용적이어야한다고 말하는 이유입니다. 이러한 규칙은 일반적으로 “never”또는 “always”상황이 아니라 일반적으로 광범위한 상황에 적합한 경향이있는 일반 지침을 체계화하는 데 도움이되며 초보자가 맹목적으로 따라갈 때 훨씬 더 멀어 질 수 있습니다. 정당한 이유없이 그들에 대항하여 선택하는 초보자보다 더 나은 결과. 때로는 규칙을 위반할 때 잘못된 선택을 수반하는 명백한 실패보다는 단순히 표준 이하의 결과로 이어지는 규칙을 체계화합니다.

따라서 일반적인 규칙은 표면에있는 것으로 보이는 절대적인 모달 제안이 아니라 표준 상용구를 사용하여 다음과 같은 규칙을 간단하게 제공합니다.

특정 상황에서이 지침이 잘못되었다고 말할 수있는 능력이없고 자신에게 옳다는 것을 입증 한 경우 $ {RULE}

물론 ls$ {RULE} 대신 “never parse output”을 대체 할 수 있습니다. 🙂

오 예! 무엇 에 대해 구문 분석 ls출력을?

글쎄, 모든 것을 감안할 때 … 나는이 규칙이 좋은 규칙이라는 것이 분명하다고 생각합니다. 우선, 실제 규칙은 위에서 설명한 것처럼 관용적 인 것으로 이해되어야합니다 …

그러나 특정 경우에 쉘 스크립트가 깨질 수 있는지 알기 위해 쉘 스크립팅에 능숙해야하는 것은 아닙니다. 또한 테스트에서 깨뜨 리려고 할 때 잘못되었다고 말하는 데 많은 기술이 필요합니다 ! 그리고 필자는 그러한 기사의 청중 대부분 («의 결과를 파싱하지 마십시오 ls!» 와 같은 조언을 제공 ) 은 그러한 일을 할 수 없으며 그러한 기술을 가진 사람들은 그들은 스스로 알아 내고 어쨌든 규칙을 무시합니다.

그러나 …이 질문을 보아라. 아마 기술을 가진 사람들조차도 그렇게하는 것이 나쁜 부름이라고 생각했다. 그리고 질문의 저자가 현재의 가장 좋은 예를 찾기 위해 얼마나 많은 노력을 기울였습니까! 나는 거기에있는 사람들의 99 %가 잘못하고 잠재적으로 매우 나쁜 결과를 초래할 것이라는 문제에 대해 당신을 보증합니다 ! 결정된 방법이 좋은 것으로 밝혀 지더라도; lsIT (또는 다른 개발자 )가 파싱 ​​아이디어를 전체적으로 채택하고 많은 테스트 (특히 시간 테스트)를 견딜 수 있고 마지막으로 ‘공통 기술’상태로 졸업 할 때까지는 많은 사람들이 그것을 시도하고 그것을 잘못 얻을 수 있습니다 …

그래서 나는 것을 …. 마지막으로 한 번 반복한다 특히이 경우 , 이유를 ” 결코 구문 분석하지 ls출력을!” 그것을 표현 하는 올바른 방법입니다.

[업데이트 2014-05-18 : OP의 의견에 대한 답변 (위)에 대한 명확한 추론; 다음은 OP가 어제 질문에 추가 한 것에 대한 답변입니다.]

[업데이트 2014-11-10 : 헤더 추가 및 재구성 / 리팩토링 된 콘텐츠; 그리고 : 재 포맷, 리워드, 명확화 및 음 … “간결한 구체화”… 나는 이것이 약간의 재 작업으로 바뀌었지만 간단하게 정리되도록 의도했습니다. 나는 그것을 미안한 상태로 남겨 두었으므로 주로 주문을 시도했다. 나는 첫 번째 부분을 그대로 두는 것이 중요하다고 생각했다. 따라서 두 가지 사소한 변경, 중복은 제거되었지만 ‘그것’이 강조되었습니다.]

† 나는 원래이 내용을 내 원본에 대한 설명으로 만 의도했다. 그러나 반영시 다른 추가 사항을 결정했습니다.

게시물에 대한 지침 은 https://unix.stackexchange.com/tour 를 참조 하십시오.