33 - flow control: for loop (The Linux command line book)
33. Flow control: looping with for
for loop는 이전에 다룬 while과 until과는 다르게 processing sequence를 제공한다.
for: traditional shell form
전통적인 형태의 for
문은 다음과 같이 사용.
for variable [in words]; do
commands
done
for문은 command line에서도 유용하게 사용될 수 있다.
[me@linuxbox ~]$ for i in A B C D; do echo $i; done
A
B
C
D
for
문의 강력한 기능 중 하나는 word list를 동적으로 만들 수 있다는 점. brace expansion을 사용 가능.
[me@linuxbox ~]$ for i in {A..D}; do echo $i; done
A
B
C
D
혹은 pathname expansion을 사용할 수 있다.
[me@linuxbox ~]$ for i in distros*.txt; do echo "$i"; done
distros-by-date.txt
distros-dates.txt
distros-key-names.txt
distros-key-vernums.txt
distros-names.txt
distros.txt
distros-vernums.txt
distros-versions.txt
다른 흔한 예시는 command substitution이다.
#!/bin/bash
# longest-word: find longest string in a file
# if "$1" is not null string
while [[ -n "$1" ]]; do
# if "$1" has read permission
if [[ -r "$1" ]]; then
max_word=
max_len=0
for i in $(strings "$1"); do
# count the letters of the filename
len="$(echo -n "$i" | wc -c)"
if (( len > max_len )); then
max_len="$len"
max_word="$i"
fi
done
echo "$1: '$max_word' ($max_len characters)"
fi
shift
done
위 예시는 특정 파일에서 가장 긴 단어를 찾는 스크립트이다.
GUN builtin package인 strings
프로그램을 사용해서 읽을 수 있는 파일의 단어 리스트를 생성하고, for문에서 각 단어를 보고 가장 긴 단어인지 판단한다.
bash operator examples: https://linuxhint.com/bash_operator_examples/#
while 대신 for를 사용하여 받은 인자를 처리하는것도 가능.
#!/bin/bash
# longest-word2: find longest string in a file
for i; do
if [[ -r "$1" ]]; then
max_word=
max_len=0
for j in $(strings "$i"); do
len="$(echo -n "$j" | wc -c)"
if (( len > max_len )); then
max_len="$len"
max_word="$j"
fi
done
echo "$i: '$max_word' ($max_len characters)"
fi
done
for: C Language form
최근 버전의 bash는 C언어에서 사용하는 형태의 두번째 for 명령어 문법을 지원한다.
for (( expression1; expression2; expression3 )); do
commands
done
이는 다음 코드와 동일한 의미.
(( expression1 ))
while (( expression2 )); do
commands
(( expression3 ))
done
expression1은 for loop의 조건을 initialize하기 위해 쓰이고, expression2는 for loop를 종료시킬 때 쓰인다. expression3은 각 loop의 종료에 실행된다.
아래는 간단한 예시
#!/bin/bash
# simple_counter: demo of C style for command
for (( i=0; i<5; i=i+1 )); do
echo $i
done
Summing up
앞에서 다룬 for 명령어를 통해 기존의 sys_info_page 스크립트를 업그레이드 시킬 수 있다.
기존에 아래의 코드로 되어있는데,
report_home_space () {
if [[ "$(id -u)" -eq 0 ]]; then
cat <<- _EOF_
<h2>Home Space Utilization (All Users)</h2>
<pre>$(du -sh /home/*)</pre>
_EOF_
else
cat <<- _EOF_
<h2>Home Space Utilization ($USER)</h2>
<pre>$(du -sh "$HOME")</pre>
_EOF_
fi
return
}
이를 각 유저의 홈 디렉토리를 순회하면서 각각이 가진 디렉토리와 파일들의 숫자를 제공하게 수정해보자.
report_home_space () {
local format="%8s%10s%10s\n"
local i dir_list total_files total_dirs total_size user_name
if [[ "$(id -u)" -eq 0 ]]; then
dir_list=/home/*
user_name="All Users"
else
dir_list="$HOME"
user_name="$USER"
fi
echo "<h2>Home Space Utilization ($user_name)</h2>"
for i in $dir_list; do
total_files="$(find "$i" -type f | wc -l)"
total_dirs="$(find "$i" -type d | wc -l)"
total_size="$(du -sh "$i" | cut -f 1)"
echo "<h3>$i</h3>"
echo "<pre>"
printf "$format" "Dirs" "Files" "Size"
printf "$format" "----" "-----" "----"
printf "$format" "$total_dirs" "$total_files" "$total_size"
echo "</pre>"
done
return
}