쉘 스크립트에서 두 개의 반복 가능한 객체 세트를 반복하는 방법은 무엇입니까?

쉘 스크립트에서 두 개의 반복 가능한 객체 세트를 반복하는 방법은 무엇입니까?

일반적으로 특정 작업을 위한 쉘 스크립트를 작성할 때 다음과 같은 파일 목록을 만듭니다.

#/bin/sh
read -d '' imagefiles <<EOF

./01/IMG0000.jpg
./01/IMG0001.jpg
./01/IMG0002.jpg
./01/IMG0003.jpg
./01/IMG0004.jpg
./01/IMG0005.jpg
./01/IMG0006.jpg
./01/IMG0007.jpg
(a whole bunch of files down to ./10/IMG0102.jpg)

EOF

for i in $imagefiles
  for j in range(len(commands))
do

mv $i ./$j.jpg

  done
done

이 경우 출력을 반복할 수 있기를 원 seq하지만 Gilles가 제안한 대로 이 부분을 Python으로 작성하세요(예, 각 명령이 j번 실행되어 약 100,000번 실행된다는 것을 알고 있습니다). 이전에는 736개의 파일을 순서대로 이름을 바꿨는데 지금은 이름을 바꿀 파일이 1000개가 넘습니다. 이 작업을 수행하는 더 좋은 방법이 있다고 확신하지만(주저하지 말고 알려주세요) 명령 목록과 기타 반복 가능한 항목을 반복하는 방법을 아는 것도 좋을 것입니다.

답변1

좋습니다. 두 개의 반복 가능 항목을 압축하려고 합니다. 즉, 추가 카운터를 사용하여 여러 문자열을 반복하는 루프를 원합니다. 카운터를 구현하는 것은 매우 쉽습니다.

n=0
for x in $commands; do
  mv -- "$x" "$n.jpg"
  n=$(($n+1))
done

이는 반복하려는 요소에 공백(또는 와일드카드)이 포함되어 있지 않은 경우에만 작동합니다. 항목이 줄바꿈으로 구분된 경우 와일드카드를 끄고 줄바꿈으로만 분할하세요.

n=0
IFS='
'; set -f
for x in $commands; do
  mv -- "$x" "$n.jpg"
  n=$(($n+1))
done
set +f; unset IFS

데이터를 한 번만 반복해야 한다면 루프를 실행하세요 read(참조:while IFS= read대신 왜 그렇게 자주 사용됩니까 IFS=; while read..?자세한 설명은)

n=0
while IFS= read -r x; do
  mv -- "$x" "$n.jpg"
  n=$(($n+1))
done <<EOF
EOF

배열(bash, ksh 또는 zsh)이 있는 셸을 사용하는 경우 배열에 요소를 저장합니다. zsh에서 setopt ksh_arrays0부터 시작하는 번호가 매겨진 배열 요소를 실행하거나 1부터 시작하는 배열 요소 번호 매기기를 시작하도록 코드를 조정합니다.

commands=(
    ./01/IMG0000.jpg
)
n=0
while [[ $n -lt ${#commands} ]]; do
  mv -- "${commands[$n]}" "$n.jpg"
done

답변2

쉘이 이면 bash이 프로그램을 실행할 필요가 없습니다 seq. 그냥 사용

for i in {1..736}
  do

앞에 0이 있는 시퀀스를 원하면 {001..736}(even {0001..0736})만 사용하세요.

또한 가능하면 백틱(이것이 어떻게 일을 엉망으로 만드는지 보려면 이 질문을 참조하세요.).

또 다른 점은 파일 그룹을 조작하려는 경우 이 기능이 유용할 수 있다는 것입니다.

for file in /some/path/*
  do

모든 파일에서 작동합니다(및 폴더)디렉토리에 /some/path/. 범위를 파일로만 좁히려면 다음 [ -f "$file" ]과 같은 유사한 테스트를 사용할 수 있습니다.

for file in /some/path/*
  do
  [ -f "$file" ] || continue
  (do your stuff here)

또한 구성은 /some/path/*와 같은 셸 모드를 통해 조정될 수 있습니다./some/path[123]/*/some/path[A-Z]/b*[e-g]*/some/path{1,5,23}/*

질문의 첫 번째 부분에 관한 한 다음 과 같이 중첩된 for(또는 임의의) 루프를 사용할 수 있습니다.while

for cm in $commands; do
 for file in /some/path[ab]{1,4,2}/*.log; do
    mv "${file}" "${file//text/replacement}"
 done
done

답변3

Bash에서는 여러 작업을 병렬로 반복할 수 없다고 생각합니다.

시작하겠습니다 i=1. 그런 다음 파일 목록이 반복되어 let i=$i+1루프에 포함됩니다. $i -ge 736또한 루프 카운트 이후 입력된 항목에 대한 반복을 중지하려는 경우 루프를 중단하는 테스트도 포함됩니다.

i=0
for file in ./{01..10}/*jpg; do
    let i=$i+1
    mv "$file" "$i-$file"
done

X 파일을 닫으려고 하면 다음과 같은 테스트를 사용할 수 있습니다.

[[ $i -ge 736 ]] && return || let i=$i+1

답변4

Bash는 배열을 지원합니다:

http://tldp.org/LDP/abs/html/arrays.html

또는

COUNT=0
for i in `ls *.txt`
do
  COUNT=`expr $COUNT + 1`
  mv "$i" "$COUNT-$i"
done

그러면 a.txt b.txt c.txt 파일의 이름이 1-a.txt 2-b.txt 3-c.txt로 변경됩니다.

관련 정보