bash에서 파일을 만들거나 자르거나 덮어 쓸 수 있는지 어떻게 확인합니까?


15

사용자는 스크립트의 어느 시점에서 foo.sh file.txt또는 처럼 파일 경로를 만들거나 덮어 쓰는 파일 경로로 내 스크립트를 호출합니다 foo.sh dir/file.txt.

작성 또는 덮어 쓰기 동작은 >출력 경로 재 지정 연산자 의 오른쪽에 파일을 배치 하거나 인수로 파일을 전달하기 위한 요구 사항과 매우 유사합니다 tee(사실, 파일을 인수로 전달하는 tee것은 정확히 내가 수행하는 작업입니다) ).

스크립트의 장에 들어가기 전에 파일 만들거나 덮어 쓸 수는 있지만 실제로 만들지는 않는지 합리적으로 확인하고 싶습니다 . 이 검사는 완벽 할 필요는 없으며 예, 검사와 파일이 실제로 작성된 지점 사이에서 상황이 바뀔 수 있다는 것을 알고 있습니다. 그러나 여기서는 최선의 노력 유형 솔루션으로 괜찮 으므로 조기에 구제 할 수 있습니다 파일 경로가 유효하지 않은 경우

파일을 만들 수없는 이유의 예 :

  • 파일에 디렉토리 구성 요소가 포함되어 dir/file.txt있지만 디렉토리 dir가 존재하지 않습니다.
  • 지정된 디렉토리 (또는 디렉토리가 지정되지 않은 경우 CWD)에 대한 쓰기 권한이 사용자에게 없습니다.

그렇습니다. "앞에서"권한을 확인하는 것이 UNIX Way ™ 가 아니라는 것을 알고 작업을 시도하고 나중에 용서를 구해야합니다. 그러나 내 특정 스크립트에서 이것은 나쁜 사용자 경험으로 이어지고 책임있는 구성 요소를 변경할 수 없습니다.


인수가 항상 현재 디렉토리를 기반으로합니까? 아니면 사용자가 전체 경로를 지정할 수 있습니까?
Jesse_b

@Jesse_b-사용자가 같은 절대 경로를 지정할 수 있다고 가정합니다 /foo/bar/file.txt. 기본적으로 명령 줄에서 전달 되는 위치 tee와 같은 경로를 전달합니다. 그것은 절대 경로와 상대 경로 모두에서 "그냥 작동"해야합니까? tee $OUT_FILEOUT_FILE
BeeOnRope

@BeeOnRope, 당신 tee -- "$OUT_FILE"은 적어도 필요하지 않습니다 . 파일이 이미 존재하지만 일반 파일이 아닌 경우 (디렉토리, symlink, fifo)?
Stéphane Chazelas

@ StéphaneChazelas-잘 사용하고 tee "${OUT_FILE}.tmp"있습니다. 파일이 이미 존재하는 경우 tee덮어 씁니다.이 경우 원하는 동작입니다. 그것이 디렉토리 tee라면 실패 할 것입니다. symlink 100 % 확실하지 않습니까?
BeeOnRope

답변:


11

명백한 테스트는 다음과 같습니다.

if touch /path/to/file; then
    : it can be created
fi

그러나 실제로 파일이 없으면 파일을 만듭니다. 우리는 스스로를 정리할 수 있습니다.

if touch /path/to/file; then
    rm /path/to/file
fi

그러나 이것은 이미 존재하는 파일을 제거 할 것입니다.

그러나 우리는이 문제를 해결할 방법이 있습니다.

if mkdir /path/to/file; then
    rmdir /path/to/file
fi

해당 디렉토리의 다른 객체와 이름이 같은 디렉토리를 가질 수 없습니다. 디렉토리를 만들 수는 있지만 파일을 만들 수없는 상황은 생각할 수 없습니다. 이 테스트가 끝나면 스크립트를 사용하여 기존 방식을 자유롭게 만들고 /path/to/file원하는대로 작업 할 수 있습니다.


2
그것은 너무 많은 문제를 깔끔하게 처리합니다! 비정상적인 솔루션이 답변의 길이를 초과 할 수 있음을 설명하고 정당화하는 코드 설명입니다. :-)
jpaugh

나는 또한 if mkdir /var/run/lockdir잠금 테스트로 사용 했다. 이것은 원자 if ! [[ -f /var/run/lockfile ]]; then touch /var/run/lockfile적이 지만 테스트와 touch문제의 스크립트 인스턴스가 시작될 수있는 시간 사이에는 시간이 조금 걸립니다 .
DopeGhoti

8

내가 수집하는 것에서 사용할 때 확인하고 싶습니다.

tee -- "$OUT_FILE"

( ---로 시작하는 파일 이름에 대해서는 또는 작동하지 않습니다), tee쓰기 위해 파일을 여는 데 성공합니다.

그게 그거야:

  • 파일 경로의 길이가 PATH_MAX 제한을 초과하지 않습니다
  • 파일이 존재하고 (symlink 확인 후) 디렉토리 유형이 아니며 쓰기 권한이 있습니다.
  • 파일이 존재하지 않는 경우 파일의 dirname은 (symlink 확인 후) 디렉토리로 존재하며 파일에 대한 쓰기 및 검색 권한이 있으며 파일 이름 길이는 디렉토리가있는 파일 시스템의 NAME_MAX 제한을 초과하지 않습니다.
  • 또는 파일이 존재하지 않고 심볼릭 링크 루프는 아니지만 바로 위의 기준을 충족하는 파일을 가리키는 심볼릭 링크

vfat, ntfs 또는 hfsplus와 같은 파일 시스템에는 파일 이름에 포함될 수있는 바이트 값, 디스크 할당량, 프로세스 제한, selinux, apparmor 또는 기타 보안 메커니즘, 전체 파일 시스템, inode가 남지 않은 장치, 장치 등이 제한되는 파일 시스템은 무시합니다. 어떤 이유로 프로세스가 열릴 수있는 실행 파일 인 다른 이유로 인해 열 수없는 파일은 파일을 열거 나 만드는 기능에도 영향을 줄 수 있습니다.

zsh:

zmodload zsh/system
tee_would_likely_succeed() {
  local file=$1 ERRNO=0 LC_ALL=C
  if [ -d "$file" ]; then
    return 1 # directory
  elif [ -w "$file" ]; then
    return 0 # writable non-directory
  elif [ -e "$file" ]; then
    return 1 # exists, non-writable
  elif [ "$errnos[ERRNO]" != ENOENT ]; then
    return 1 # only ENOENT error can be recovered
  else
    local dir=$file:P:h base=$file:t
    [ -d "$dir" ] &&    # directory
      [ -w "$dir" ] &&  # writable
      [ -x "$dir" ] &&  # and searchable
      (($#base <= $(getconf -- NAME_MAX "$dir")))
    return
  fi
}

에서 bash또는 본쉘 같은 그냥 교체

zmodload zsh/system
tee_would_likely_succeed() {
  <zsh-code>
}

와:

tee_would_likely_succeed() {
  zsh -s -- "$@" << 'EOF'
  zmodload zsh/system
  <zsh-code>
EOF
}

zsh여기 의 특정 기능은 $ERRNO(마지막 시스템 호출의 오류 코드를 표시 함) $errnos[]관련 배열을 해당 표준 C 매크로 이름으로 변환합니다. 그리고 $var:h(csh에서) 및 $var:P(zsh 5.3 이상 필요).

bash에는 아직 동등한 기능이 없습니다.

$file:hdir=$(dirname -- "$file"; echo .); dir=${dir%??}또는 GNU dirname: 로 대체 할 수 있습니다 IFS= read -rd '' dir < <(dirname -z -- "$file").

의 경우 파일에서 $errnos[ERRNO] == ENOENT접근 ls -Ld하고 오류 메시지가 ENOENT 오류에 해당하는지 확인 하는 방법이 있습니다 . 그래도 믿을 수 있고 휴대하기가 까다 롭습니다.

한 가지 방법은 다음과 같습니다.

msg_for_ENOENT=$(LC_ALL=C ls -d -- '/no such file' 2>&1)
msg_for_ENOENT=${msg_for_ENOENT##*:}

(오류 메시지 가정 syserror()번역 ENOENT하고 그 번역이 포함되지 않는 :대신, 다음) 및 [ -e "$file" ]수행 :

err=$(ls -Ld -- "$file" 2>&1)

와 함께 ENOENT 오류를 확인하십시오.

case $err in
  (*:"$msg_for_ENOENT") ...
esac

$file:P부분은 bash특히 FreeBSD 에서 가장 까다로운 부분입니다 .

FreeBSD에는 옵션 을 허용 하는 realpath명령과 readlink명령이 -f있지만 파일이 해석되지 않는 심볼릭 링크 인 경우에는 사용할 수 없습니다. 그와 같은의 perlCwd::realpath().

pythonos.path.realpath()유사에 작동하는 것처럼 않는 zsh $file:P정도의 적어도 하나 개의 버전 가정, python설치하고는있다 python, 당신이 할 수있는 (안 FreeBSD의에 주어진 인) 중 하나를 의미 명령 :

dir=$(python -c '
import os, sys
print(os.path.realpath(sys.argv[1]) + ".")' "$dir") || return
dir=${dir%.}

그러나에서의 모든 작업을 수행 할 수도 있습니다 python.

또는 모든 코너 케이스를 처리하지 않기로 결정할 수 있습니다.


예, 당신은 나의 의도를 올바르게 이해했습니다. 사실, 원래의 질문은 분명했다 : 나는 원래에 대해 언급 생성 파일을, 실제로 나는 그것을 사용하고 tee요구 사항이 파일이 생성 될 수 있음을 정말 그래서 경우에 존재하지 않는, 또는 제로 덮어 쓰기로 절단 할 수있다 그렇다면 (또는 그렇지 않으면 tee처리합니다).
BeeOnRope 1

마지막 편집으로 형식이 지워진 것 같습니다
D. Ben Knoble

감사합니다, @bishop, @ D.BenKnoble, 편집 참조.
Stéphane Chazelas

1
@DennisWilliamson, 그렇습니다. 쉘은 프로그램을 호출하는 도구이며 스크립트에서 호출하는 모든 프로그램은 스크립트가 작동하도록 설치해야합니다. macOS는 기본적으로 bash 및 zsh가 설치되어 제공됩니다. FreeBSD는 둘 다 제공되지 않습니다. OP는 bash에서 그렇게하고 싶은 이유가있을 수 있습니다. 아마도 이미 작성된 bash 스크립트에 추가하려는 것일 수 있습니다.
Stéphane Chazelas

1
다시 @pipe는 쉘이 명령 해석기입니다. 당신은 다른 언어의 통역이 좋아 된 invoke 여기에 기록 된 많은 쉘 코드 발췌 볼 수 있습니다 perl, awk, sed또는 python(또는 sh, bash...)을. 셸 스크립팅은 작업에 가장 적합한 명령을 사용하는 것입니다. 여기에서도 perl동등한하지 않는 zsh$var:P(의 Cwd::realpathBSD와 같은 동작합니다을 realpath또는 readlink -f당신이 원하는 것 동안은 GNU처럼 행동하는 readlink -fpython'의 os.path.realpath())
스테판 Chazelas가

6

고려해야 할 한 가지 옵션 은 파일을 조기에 작성 하지만 나중에 스크립트에서 채우는 것입니다. 이 exec명령을 사용하여 파일 설명자 (예 : 3, 4 등)에서 파일을 연 다음 나중에 파일 설명자 ( >&3등)로 리디렉션을 사용 하여 해당 파일에 내용을 쓸 수 있습니다.

다음과 같은 것 :

#!/bin/bash

# Open the file for read/write, so it doesn't get
# truncated just yet (to preserve the contents in
# case the initial checks fail.)
exec 3<>dir/file.txt || {
    echo "Error creating dir/file.txt" >&2
    exit 1
}

# Long checks here...
check_ok || {
    echo "Failed checks" >&2
    # cleanup file before bailing out
    rm -f dir/file.txt
    exit 1
}

# We're ready to write, first truncate the file.
# Use "truncate(1)" from coreutils, and pass it
# /dev/fd/3 so the file doesn't need to be reopened.
truncate -s 0 /dev/fd/3

# Now populate the file, use a redirection to write
# to the previously opened file descriptor.
populate_contents >&3

a trap를 사용하여 오류가 발생했을 때 파일을 정리할 수도 있습니다 . 이는 일반적인 관행입니다.

이렇게 하면 파일을 만들 수있는 권한에 대한 실제 검사를받을 수 있으며, 동시에 실패 할 경우 긴 검사를 기다리는 데 시간을 소비하지 않을 정도로 빨리 파일을 수행 할 수 있습니다.


업데이트 : 검사가 실패 할 때 파일을 방해 하지 않으려면 파일을 즉시 자르지 않는 bash의 fd<>file리디렉션 을 사용 하십시오. (우리는 파일을 읽는 것에 신경 쓰지 않습니다. 이것은 해결 방법 일 뿐이므로 잘리지 않습니다. 추가 >>하면 아마도 작동하지만 O_APPEND 플래그를 유지하면서 조금 더 우아하게 찾는 경향이 있습니다 그림의.)

내용을 바꿀 준비가되면 먼저 파일을 잘라 내야합니다 (그렇지 않으면 이전에 파일에 있던 것보다 적은 바이트를 쓰면 후행 바이트가 그대로 유지됩니다). truncate (1) 그런 목적으로 coreutils에서 명령을 실행하면 /dev/fd/3의사 파일을 사용하여 열린 파일 설명자를 전달할 수 있으므로 파일을 다시 열 필요가 없습니다. (다시 말해서 기술적으로 더 간단한 : >dir/file.txt것이 작동하지만 파일을 다시 열지 않아도되는 것이 더 우아한 솔루션입니다.)


나는 이것을 고려했지만 문제는 파일을 만들 때와 나중에 쓸 시점 사이에 다른 무고한 오류가 발생하면 사용자가 지정된 파일을 덮어 썼음을 알게되어 화가 날 것입니다 .
BeeOnRope

1
@BeeOnRope 파일을 방해하지 않는 다른 옵션은 아무것도 추가 하지 않는 것입니다 : echo -n >>file또는 true >> file. 물론 ext4에는 추가 전용 파일이 있지만이 오 탐지로 살아갈 수 있습니다.
mosvy

1
@BeeOnRope (a) 기존 파일 또는 (b) (완전한) 새 파일을 보존해야하는 경우 요청한 것과 다른 질문입니다. 이에 대한 좋은 대답은 새 파일을 my-file.txt.backup만들기 전에 기존 파일을 새 이름 (예 :)으로 옮기는 것입니다. 또 다른 해결책은 동일한 폴더의 임시 파일에 새 파일을 작성한 다음 스크립트의 나머지 부분이 성공한 후 이전 파일 위에 복사하는 것입니다 .- 마지막 작업이 실패한 경우 사용자는 손실없이 수동으로 문제를 해결할 수 있습니다 그의 진보.
jpaugh

1
@BeeOnRope 만약 당신이 "원자 교체"라우트 (좋은 것입니다!)를 간다면 일반적으로 최종 파일과 같은 디렉토리에 임시 파일을 작성하고 싶을 것입니다. (2) 성공하려면) 고유 이름을 사용하십시오 (따라서 두 개의 스크립트 인스턴스가 실행중인 경우 서로의 임시 파일을 클로버하지 않습니다.) 동일한 디렉토리에 쓰기 위해 임시 파일을 여는 것이 일반적으로 좋은 표시입니다. 나중에 이름을 바꿀 수 있습니다 (최종 대상이 존재하고 디렉토리 인 경우를 제외하고), 어느 정도까지도 질문을 처리합니다.
filbranden

1
@jpaugh-나는 그것을 꺼려합니다. 필연적으로 더 높은 수준의 문제를 해결하려는 시도로 이어질 것인데, "어떻게 확인할 수 있습니까?"라는 질문과 관련이없는 솔루션을 인정할 수 있습니다. 내 높은 수준의 문제가 무엇이든 관계 없이이 질문은 당신이 합리적으로하고 싶을만한 일이라고 생각합니다. "내가 스크립트에서 가지고있는이 특정 문제를 해결하기 위해"변경 한 경우 해당 특정 질문에 대답하는 사람들에게는 불공평 할 것입니다. 요청을 받았기 때문에 여기에 이러한 세부 사항을 포함 시켰지만 기본 질문을 변경하고 싶지 않습니다.
BeeOnRope

4

DopeGhoti의 솔루션이 더 낫다고 생각하지만 이것이 작동해야합니다.

file=$1
if [[ "${file:0:1}" == '/' ]]; then
    dir=${file%/*}
elif [[ "$file" =~ .*/.* ]]; then
    dir="$(PWD)/${file%/*}"
else
    dir=$(PWD)
fi

if [[ -w "$dir" ]]; then
    echo "writable"
    #do stuff with writable file
else
    echo "not writable"
    #do stuff without writable file
fi

첫 번째 if 구문은 인수가 전체 경로인지 확인하고 (로 시작 /) dir변수를 디렉토리 경로로 설정합니다 /. 그렇지 않으면 인수가 a로 시작하지 않지만 (하위 디렉토리 지정)을 /포함하는 경우 현재 작업 디렉토리 + 하위 디렉토리 경로로 설정됩니다. 그렇지 않으면 현재 작업 디렉토리를 가정합니다. 그런 다음 해당 디렉토리가 쓰기 가능한지 확인합니다./dir


4

test아래에 설명 된 것처럼 일반 명령을 사용하는 것은 어떻습니까?

FILE=$1

DIR=$(dirname $FILE) # $DIR now contains '.' for file names only, 'foo' for 'foo/bar'

if [ -d $DIR ] ; then
  echo "base directory $DIR for file exists"
  if [ -e $FILE ] ; then
    if [ -w $FILE ] ; then
      echo "file exists, is writeable"
    else
      echo "file exists, NOT writeable"
    fi
  elif [ -w $DIR ] ; then
    echo "directory is writeable"
  else
    echo "directory is NOT writeable"
  fi
else
  echo "can NOT create file in non-existent directory $DIR "
fi

나는이 답변을 거의 복제했습니다! 니스 도입,하지만 당신은 말할 수도 man test, 그것은 [ ](더 이상 일반적이지 지식) 시험에 해당합니다. 후손을위한 정확한 사례를 다루기 위해 열등한 대답에 사용하려고 한 라이너는 다음과 같습니다.if [ -w $1] && [ ! -d $1 ] ; then echo "do stuff"; fi
Iron Gremlin

4

사용자 경험이 귀하의 질문을 주도하고 있다고 언급했습니다. 기술적 인 측면에서 좋은 답변을 얻었으므로 UX 각도에서 대답하겠습니다.

사전 점검을 수행하는 대신 결과를 임시 파일 에 쓴 다음 마지막에 사용자가 원하는 파일에 결과를 넣는 것은 어떻습니까? 처럼:

userfile=${1:?Where would you like the file written?}
tmpfile=$(mktemp)

# ... all the complicated stuff, writing into "${tmpfile}"

# fill user's file, keeping existing permissions or creating anew
# while respecting umask
cat "${tmpfile}" > "${userfile}"
if [ 0 -eq $? ]; then
    rm "${tmpfile}"
else
    echo "Couldn't write results into ${userfile}." >&2
    echo "Results available in ${tmpfile}." >&2
    exit 1
fi

이 접근 방식의 장점은 정상적인 해피 패스 시나리오에서 원하는 작업을 생성하고 테스트 및 설정 원 자성 문제를 회피하며 필요한 경우 작성하는 동안 대상 파일의 권한을 유지하며 구현하기가 쉽지 않습니다.

참고 : 우리가 사용했다 mv 했다면 임시 파일의 권한을 유지하고 싶습니다. 우리는 원하지 않습니다. 권한은 대상 파일에 설정된 권한을 유지하려고합니다.

이제 나쁜 점 : 공간 ( cat .. >구문)의 두 배가 필요하고 필요한 시점에 대상 파일을 쓸 수없는 경우 사용자가 수동 작업을 수행하도록하고 임시 파일을 남겨 둡니다 (보안이있을 수 있음) 또는 유지 보수 문제).


사실, 이것은 내가 지금하고있는 일입니다. 대부분의 결과를 임시 파일에 쓴 다음 마지막 처리 단계를 수행하고 결과를 최종 파일에 씁니다. 문제는 마지막 단계가 실패 할 경우 스크립트 시작시 조기에 구제하고 싶다는 것입니다. 스크립트는 몇 분 또는 몇 시간 동안 무인으로 실행될 수 있으므로 실제로 실패 할 운명이라는 것을 미리 알고 싶습니다!
BeeOnRope

물론, 실패 할 수있는 여러 가지 방법이 있습니다. 디스크가 가득 찼을 때, 업스트림 디렉터리가 제거 될 수 있으며, 권한이 변경 될 수 있으며, 대상 파일이 다른 중요한 것들에 사용될 수 있으며 사용자가 동일한 파일을 할당하여 잊어 버렸습니다. 조작. 우리가 순수한 UX 관점에서 이것에 대해 이야기한다면, 아마도 옳은 일은 그것을 작업 제출처럼 취급하는 것입니다. 마지막으로, 그것이 제대로 완료되었다는 것을 알게되면, 결과 컨텐츠가 어디에 있는지 제공하고 제공하십시오. 제안 그들에 대한 명령은 스스로를 이동합니다.
주교

이론적으로는, 이것이 실패 할 수있는 무한한 방법이 있습니다. 실제로, 이것이 실패하는 압도적 인 대다수의 시간은 제공된 경로가 유효하지 않기 때문입니다. 일부 악성 사용자가 작업 도중에 작업을 중단하기 위해 FS를 동시에 수정하는 것을 합리적으로 막을 수는 없지만 유효하지 않거나 쓸 수없는 경로의 # 1 실패 원인을 확실히 확인할 수 있습니다.
BeeOnRope

2

TL; DR :

: >> "${userfile}"

달리 <> "${userfile}"거나 touch "${userfile}",이 파일의 타임 스탬프에 대한 가짜 수정을하지 않으며 또한 쓰기 전용 파일과 함께 작동합니다.


OP에서 :

파일을 만들거나 덮어 쓸 수 있지만 실제로 만들지는 않는지 합리적으로 확인하고 싶습니다.

UX 관점 에서 귀하의 의견에서 내 대답에 이르기까지 :

이것이 실패하는 압도적 인 대다수는 제공된 경로가 유효하지 않기 때문입니다. 작업 도중에 작업을 중단하기 위해 일부 FS를 동시에 수정하는 악의적 인 사용자를 합리적으로 막을 수는 없지만 유효하지 않거나 쓸 수없는 경로의 # 1 실패 원인을 확실히 확인할 수 있습니다.

신뢰할 수있는 유일한 테스트는 open(2)경로, 소유권, 파일 시스템, 네트워크, 보안 컨텍스트 등과 같은 쓰기 가능성에 대한 모든 질문을 해결하기 때문에 파일 대한 . 다른 테스트는 쓰기 가능성의 일부를 다루지 만 다른 테스트는 다루지 않습니다. 테스트의 하위 세트를 원할 경우 궁극적으로 중요한 것을 선택해야합니다.

그러나 여기 또 다른 생각이 있습니다. 내가 이해 한 것에서 :

  1. 콘텐츠 제작 과정이 오래 지속되고
  2. 대상 파일은 일관된 상태로 유지되어야합니다.

# 1 때문에이 사전 검사를 수행하려고하고 # 2 때문에 기존 파일로 바이올린을 사용하고 싶지 않습니다. 그렇다면 왜 쉘에 파일을 열어달라고 요청하지 말고 실제로 아무것도 추가하지 않습니까?

$ tree -ps
.
├── [dr-x------        4096]  dir_r
├── [drwx------        4096]  dir_w
├── [-r--------           0]  file_r
└── [-rw-------           0]  file_w

$ for p in file_r dir_r/foo file_w dir_w/foo; do : >> $p; done
-bash: file_r: Permission denied
-bash: dir_r/foo: Permission denied

$ tree -ps
.
├── [dr-x------        4096]  dir_r
├── [drwx------        4096]  dir_w
   └── [-rw-rw-r--           0]  foo
├── [-r--------           0]  file_r
└── [-rw-------           0]  file_w

이를 통해 쓰기 가능성 질문이 원하는대로 정확하게 해결됩니다.

open("dir_w/foo", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3

파일 내용이나 메타 데이터를 수정하지 않고 자,이 접근법은 :

  • 파일이 추가 전용인지는 알려주지 않으므로 콘텐츠 작성이 끝날 때 파일을 업데이트 할 때 문제가 될 수 있습니다. 이를 어느 정도 감지 lsattr하고 그에 따라 반응 할 수 있습니다 .
  • 그러한 경우 이전에 존재하지 않는 파일을 작성합니다 rm. selective로이를 완화하십시오 .

(다른 대답으로) 가장 사용자 친화적 인 접근 방식은 사용자가 이동 해야하는 임시 파일을 작성하는 것이라고 주장하지만 , 이것이 입력을 완전히 조사 하는 데 가장 적대적인 접근 방식 이라고 생각합니다 .

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