Bash에서 배열 값 처리

Bash에서 배열 값 처리

파일 이름을 기반으로 배열을 만들려고 하는데 공백에 문제가 있습니다. 이것은 매우 일반적인 것 같습니다. 하지만 - 내가 알 수 있는 한 - 따옴표는 올바르게 설정되었으며 배열이 어떻게 구성되는지 추측합니다.

to_dump="$(find . -maxdepth 1 -print0 )"
to_dump_array=($to_dump)

read -p " ->  " final
case "$final" in
   a) for drop in "${to_dump_array[@]}" ;
      do cp "$drop" --recursive --force Destination_Folder && \
      echo "dropped \"$drop\" ;
      done ;;
   b) echo "Won't drop anything" ;;
esac

조회 쿼리에서 배열을 작성하는 더 좋은 방법이 있어야 한다고 생각합니다. 또한 내가 또 어디로 잘못 가고 있습니까?

답변1

-print0$(...)bash 변수의 문자열은 null로 끝나기 때문에 대체에 사용하면 안 됩니다 .

나는 이 질문이 묻는 것과 비슷한 대답으로 질문을 했습니다.https://stackoverflow.com/a/30469553/1091693

다음 답변을 귀하의 질문에 맞게 조정하세요.

to_dump=()
while IFS= read -r -d ''; do
  to_dump+=( "$REPLY" )
done < <(find . -maxdepth 1 -print0)

그러면 이름이 지정된 배열이 생성되고 to_dumpread명령을 사용하여 배열에서 NULL로 구분된 요소를 읽습니다 find. 여기서 파이프 대신 사용하는 이유는 < <(...)배열이 수정되는 것을 방지하는 암시적 하위 쉘을 피하기 위한 것입니다.

원래 find명령에 하나가 필요할 수도 -mindepth 1있고 .재귀적으로 복사하게 될 (현재 디렉터리)를 선택할 수도 있다는 점은 주목할 가치가 있습니다.


나는 당신이 -maxdepth 1find를 위한 인수로 사용했다는 것을 알았습니다. 아마도 이것이 더 유용할 것입니다:

shopt -s nullglob
to_dump=( * .[!.]* ..?* )

피하십시오 find. 이것은 bash 내장만 사용하고 포크하지 않으며 대부분 매우 깨끗합니다.

첫 번째 줄 shopt -s nullglob은 이 옵션을 활성화하는 bash(-only) 명령입니다 nullglob. 옵션은 아래에 설명되어 있습니다 man 1 bash.

설정된 경우, bash는 어떤 파일과도 일치하지 않는 패턴(위의 경로 이름 확장 참조)이 자신이 아닌 빈 문자열로 확장되도록 허용합니다.

간단히 말해, 입력한 파일이 *파일과 일치하지 않으면 삭제됩니다 *. 기본 동작은 *어쨌든 해당 파일을 넣는 것입니다.

두 번째 줄은 배열에 3개의 구체를 추가합니다.

  • *: 다음으로 시작하지 않는 모든 파일.
  • .[!.]*.: 하나와 하나의 비문자로 시작하는 모든 파일입니다 .. 이는 일치 .와 디렉토리를 피하기 위한 것입니다 ...
  • ..?*..: 하나 이상의 문자로 시작하는 모든 파일입니다. 이를 추가하는 이유는 이전 glob과 동일하며 누락된 경우를 포함합니다.

Bash는 glob을 배열 정의로 확장하고 올바르게 확장합니다. 공백이나 이와 유사한 분할이 없습니다.

nullglob 사용에 대한 경고: nullglob을 켜면 curl google.com/search?q=test컬이 인수를 전달하지 않았다고 불평하고 ls /var/fasdfasafs*현재 디렉터리 목록을 제공합니다. 이것이 기본적으로 켜져 있지 않은 이유 중 하나입니다.

답변2

다음과 같이 배열을 만들어 보십시오.

read -d $'\0' -r -a to_dump <<< $(find . -maxdepth 1 -print0)

답변3

 find . -maxdepth 1

...당신이 원하는 것은 다음과 같습니다.

a=()
for f in ./..?* ./.[!.]* ./*
do  [ -e "$f" ] && a+=$f
done

답변4

귀하의 스크립트가 귀하가 생각하는 대로 작동하는지 잘 모르겠습니다. 나는 이것이 null로 끝나는 find 출력을 파일 이름의 bash 배열로 변환한다고 생각하지 않습니다.

to_dump_array=($to_dump)

for 루프의 출력을 확인하여 결과를 확인했습니까?

for drop in "${to_dump_array[@]}"
do
    echo -e "$drop\n"
done

find -print0에서 배열을 채우는 방법에 대한 몇 가지 조언이 포함된 스택 오버플로가 있습니다.

https://stackoverflow.com/questions/1116992/capturing-output-of-find-print0-into-a-bash-array

for 루프의 변수에 직접 할당하는 것보다 배열 항목에 대해 배열 인덱싱을 사용하는 것이 더 나을 수도 있습니다. 이렇게 하면 적절한 분할을 위해 셸에 의존하지 않아도 됩니다.

for drop in $(seq 0 $((${#to_dump_array[@]} - 1)))
do
    cp "${to_dump_array[$drop]}"

이것은 그다지 인기가 없을 수도 있지만, 파일 이름에서 공백(및 기타 특이한 문자)을 관리하기 위해 bash 배열과 여러 이스케이프를 사용해야 하는 경우 쉘이 설계된 목적을 초과할 수 있습니다.

Python, Perl, Ruby 등이 더 빠르고 안정적이며 코드 기반을 관리하고 디버깅하기가 더 쉽다는 것을 알 수 있습니다.

나는 쉘 스크립팅에 적합한 수준을 넘어서는 경우를 알려주는 데 사용하는 여러 가지 "위험 신호"를 가지고 있습니다.

  • 모든 파일 이름 상황을 처리하기 위한 여러 수준의 이스케이프 또는 null 종료.
  • 여러 계층의 셸 함수가 서로 호출합니다.
  • 복잡한 데이터 구조. 즉, 문자열과 숫자를 넘어서는 것입니다.
  • 나는 "성능 최적화"를 수행하고 있습니다.
  • 표현식의 "라인 노이즈".

예, 위의 모든 작업을 확실히 수행할 수 있습니다. 하지만 그렇게 해야 합니까? 정말...파이썬, 펄, 루비 등. Python에서는 매우 간단합니다. 공백이나 이진 문자가 포함된 파일 이름이나 이스케이프에 대해 걱정할 필요가 없습니다.

import os

dirListing = os.listdir("somedirectory")

for eachEntry in dirlisting:
    doSomething

관련 정보