예전엔 1부터 10까지 expr를 이용해서 for문 같이 구현했었는데... 이외의 방법들도 많군요~


Bash For Loop Examples

by VIVEK GITE on OCTOBER 31, 2008 · 190 COMMENTS

How do I use bash for loop to repeat certain task under Linux / UNIX operating system? How do I set infinite loops using for statement? How do I use three-parameter for loop control expression?

A 'for loop' is a bash programming language statement which allows code to be repeatedly executed. A for loop is classified as an iteration statement i.e. it is the repetition of a process within a bash script.

For example, you can run UNIX command or task 5 times or read and process list of files using a for loop. A for loop can be used at a shell prompt or within a shell script itself.

for loop syntax

Numeric ranges for syntax is as follows:

for VARIABLE in 1 2 3 4 5 .. N
do
	command1
	command2
	commandN
done

This type of for loop is characterized by counting. The range is specified by a beginning (#1) and ending number (#5). The for loop executes a sequence of commands for each member in a list of items. A representative example in BASH is as follows to display welcome message 5 times with for loop:

#!/bin/bash
for i in 1 2 3 4 5
do
   echo "Welcome $i times"
done

Sometimes you may need to set a step value (allowing one to count by two's or to count backwards for instance). Latest bash version 3.0+ has inbuilt support for setting up ranges:

#!/bin/bash
for i in {1..5}
do
   echo "Welcome $i times"
done

Bash v4.0+ has inbuilt support for setting up a step value using {START..END..INCREMENT} syntax:

#!/bin/bash
echo "Bash version ${BASH_VERSION}..."
for i in {0..10..2}
  do
     echo "Welcome $i times"
 done

Sample outputs:

Bash version 4.0.33(0)-release...
Welcome 0 times
Welcome 2 times
Welcome 4 times
Welcome 6 times
Welcome 8 times
Welcome 10 times

The seq command (outdated)

WARNING! The seq command print a sequence of numbers and it is here due to historical reasons. The following examples is only recommend for older bash version. All users (bash v3.x+) are recommended to use the above syntax.

The seq command can be used as follows. A representative example in seq is as follows:

#!/bin/bash
for i in $(seq 1 2 20)
do
   echo "Welcome $i times"
done

There is no good reason to use an external command such as seq to count and increment numbers in the for loop, hence it is recommend that you avoid using seq. The builtin command are fast.

Three-expression bash for loops syntax

This type of for loop share a common heritage with the C programming language. It is characterized by a three-parameter loop control expression; consisting of an initializer (EXP1), a loop-test or condition (EXP2), and a counting expression (EXP3).

for (( EXP1; EXP2; EXP3 ))
do
	command1
	command2
	command3
done

A representative three-expression example in bash as follows:

#!/bin/bash
for (( c=1; c<=5; c++ ))
do
	echo "Welcome $c times..."
done

Sample output:

Welcome 1 times
Welcome 2 times
Welcome 3 times
Welcome 4 times
Welcome 5 times

How do I use for as infinite loops?

Infinite for loop can be created with empty expressions, such as:

#!/bin/bash
for (( ; ; ))
do
   echo "infinite loops [ hit CTRL+C to stop]"
done

Conditional exit with break

You can do early exit with break statement inside the for loop. You can exit from within a FOR, WHILE or UNTIL loop using break. General break statement inside the for loop:

for I in 1 2 3 4 5
do
  statements1      #Executed for all values of ''I'', up to a disaster-condition if any.
  statements2
  if (disaster-condition)
  then
	break       	   #Abandon the loop.
  fi
  statements3          #While good and, no disaster-condition.
done

Following shell script will go though all files stored in /etc directory. The for loop will be abandon when /etc/resolv.conf file found.

#!/bin/bash
for file in /etc/*
do
	if [ "${file}" == "/etc/resolv.conf" ]
	then
		countNameservers=$(grep -c nameserver /etc/resolv.conf)
		echo "Total  ${countNameservers} nameservers defined in ${file}"
		break
	fi
done

Early continuation with continue statement

To resume the next iteration of the enclosing FOR, WHILE or UNTIL loop use continue statement.

for I in 1 2 3 4 5
do
  statements1      #Executed for all values of ''I'', up to a disaster-condition if any.
  statements2
  if (condition)
  then
	continue   #Go to next iteration of I in the loop and skip statements3
  fi
  statements3
done

This script make backup of all file names specified on command line. If .bak file exists, it will skip the cp command.

#!/bin/bash
FILES="$@"
for f in $FILES
do
        # if .bak backup file exists, read next file
	if [ -f ${f}.bak ]
	then
		echo "Skiping $f file..."
		continue  # read next file and skip cp command
	fi
        # we are hear means no backup file exists, just use cp command to copy file
	/bin/cp $f $f.bak
done

Recommended readings:

  • See all sample for loop shell script in our bash shell directory.
  • man bash
  • help for
  • help {
  • help break
  • help continue

Updated for accuracy!

크리에이티브 커먼즈 라이센스
Creative Commons License


'리눅스' 카테고리의 다른 글

mysql 원격접속 오류  (0) 2017.08.26
쉘 레벨 및 변수  (0) 2017.06.09

웹 표준은 이제 더 이상 무시할 수 없는 키워드입니다. World Wide Web(WWW)의 의미대로 가능한 많은 사람이 웹을 이용하기 위해서는, 모든 브라우저에서 ‘똑같이 보이는 것’이 아니라 ‘각 브라우저에 알맞게 보이는 것’이 중요하기 때문입니다. 그래서 웹 표준에서는 구조(Constructure)와 표현(Presentation)과 행위(Behavior)를 각각 분리해서 개발하기를 권유합니다. 이렇게 하면, 각 사용자는 구조화 된 마크업에 따라 다양한 디자인을 제공받을 수 있기 때문입니다. 뿐만 아니라 사이트의 로딩속도도 빨라지고 개발과 유지보수 또한 쉬워집니다.

  • 구조 : 웹 콘텐츠에 의미를 부여하고 구조를 형성 → HTML
  • 표현 : 시각적인 디자인과 레이아웃 표현 → CSS
  • 행위 : 모든 front-end의 브라우저 상호작용을 담당 → JavaScript

이 글에서는 이 중에서 표현(Presentation)을 담당하고 있는 CSS의 '선택자(Selector)'에 대해 알아봅니다.

1. CSS 선택자(Selector)란?

선택자란 말 그대로 선택을 해주는 요소입니다. 이를 통해 특정 요소들을 선택하여 스타일을 적용할 수 있게 됩니다. 먼저 CSS에서 스타일이 어떤 방식으로 정의되는지 알아봅시다.

1.1 Rule Set

Rule Set(Rule)은 HTML페이지 안의 특정 요소들을 어떻게 렌더링(Rendering) 할 것인지 브라우저에게 알려주는 CSS 문장입니다. 스타일 규칙이라고도 불리는 이 문장은 스타일에 관한 규칙들을 집합처럼 나타냅니다.

[그림 1] Rule Set

이런 문장들을 한군데에 모으면 스타일 시트(Style Sheet)를 이루게 되어, 많은 수의 스타일 규칙들을 관리하기 쉬워집니다.

1.2 선택자(Selector)

위쪽 [그림 1]을 다시 보시면, Rule Set 제일 앞 부분의 선택자 요소를 볼 수 있는데요. 왼쪽 중괄호 "{"가 나오기 전의 부분 모두가 선택자입니다. 선택자는 Rule Set의 영향을 받는 HTML페이지 안의 특정 element들을 선택해서 선언 블록(Declaration Block)의 내용을 적용시켜 줍니다.

참고) 
@media print { background-color: transparent; } “@”키워드로 시작하는 문장은 Rule Set이 아닌 At-Rule이기 때문에 위 문장에서의 중괄호 전 부분은 선택자가 아닙니다.

2. 선택자(Selector)의 종류

디자인 요소를 의도에 알맞게 적용하기 위해서는 많은 종류의 선택자를 잘 혼합해서 사용하는 것이 중요합니다. 그 종류와 CSS 레벨, 지원하지 않는 브라우저 버전을 함께 알아봅니다.

2.1 전체 선택자(Universal Selector)

패턴의미CSS Level지원하지 않는
브라우저
*HTML페이지 내부의 모든 태그를 선택합니다.2-
/* CSS */
* { margin: 0; text-decoration: none; }

[예제 1] 전체 선택자

전체 선택자는 HTML페이지 내부의 모든 요소(태그)에 같은 CSS속성을 적용합니다. 그렇기 때문에 보통 [예제 1]처럼 margin이나 padding값을 초기화하는 등 기본값을 정해둘 때 사용합니다. 하지만 이를 사용하면 문서안의 모든 요소를 읽어내려야 하기 때문에 페이지 로딩의 속도가 느려질 수 있습니다. 따라서 자주 사용하지 않는 것이 좋습니다.

2.2 태그 선택자(Type Selector)

패턴의미CSS Level지원하지 않는
브라우저
E태그명이 E인 특정 태그를 선택합니다.2-
/* CSS */
p { background: yellowgreen; color: darkgreen; }

<!-- HTML -->  
<p>태그 선택자(Type Selector)</p>  
<div>태그 선택자(Type Selector)</div>  

[예제 2] 태그 선택자

태그 선택자는 HTML요소를 직접 지칭하는 가장 간단한 선택자입니다. [예제 2]를 보시면 CSS에서

태그에 대한 스타일만 지정이 되어있으므로,

태그에는 개발자가 지정해주는 스타일이 적용되지 않습니다.

2.3 클래스 선택자(Class Selector)

패턴의미CSS Level지원하지 않는
브라우저
.myClass클래스 속성값이 myClass으로 지정된 요소를 선택합니다.1-
/* CSS */
.class1 { background: yellowgreen; color: darkgreen; }
div.class2 { background: darkgreen; color: yellowgreen; }

<!-- HTML -->  
<p class="class1">클래스 선택자(Class Selector)</p>  
<p class="class2">클래스 선택자(Class Selector)</p>  
<div class="class2">클래스 선택자(Class Selector)</div>  

[예제 3] 클래스 선택자

클래스 선택자는 주어진 값을 class속성값으로 가진 HTML요소를 찾아 선택합니다. 이때 선택하려는 속성값 앞에 마침표를 추가해서 작성합니다. [예제 3] CSS 코드의 첫번째 스타일 규칙은 class1이라는 class 속성값을 가진 모든 태그를 선택합니다. 하지만 두번째 스타일 규칙처럼 마침표 앞에 태그를 붙여주면 범위를 그 특정 태그에 한합니다. 결국 HTML 코드의 두번째

태그 부분은 class 속성값이 class2임에도 선택되지 않습니다.

클래스 선택자를 사용하기 전에 생각해야 할 부분

  1. class요소 대신 사용할 수 있는 HTML 태그가 있는지 확인합니다. 
    한가지 예를 들어보겠습니다. heading처리한 글씨처럼 보이기 위하여 <h1>과 같은 태그 대신 class선택자를 사용하여 스타일 속성을 줄 수 있습니다. 하지만 이렇게 사용하면 스타일 시트를 적용하지 못하는 (극히 일부일지라도) 브라우저에서는 제목의 기능을 하지 못할 수 있습니다. 그래서, 가능한 올바른 HTML요소를 사용하고 스타일은 따로 적용해야 합니다. 결국 클래스는 HTML태그. 즉 구조를 대신할 수 없습니다.

  2. DOM트리 상단에 사용되는 클래스나 ID가 있는지 확인합니다. 
    불필요하게 많은 class선택자를 사용할 필요는 없습니다. DOM트리 상단에 같은 스타일을 공유하는 클래스나 ID가 있다면, 새로 클래스 선택자를 사용할 필요없이 함께 사용하면 됩니다.

2.4 ID 선택자(ID Selector)

패턴의미CSS Level지원하지 않는
브라우저
#myIdid 속성값이 myId로 지정된 요소를 선택합니다.1-
/* CSS */
#id1 { background: yellowgreen; color: darkgreen; }
div#id2 { background: darkgreen; color: yellowgreen; }

<!-- HTML -->  
<p id="id1">ID 선택자(ID Selector)</p>  
<p id="id2">ID 선택자(ID Selector)</p>  
<div id="id2">ID 선택자(ID Selector)</div>  

[예제 4] ID 선택자

ID선택자는 마침표 대신 #를 사용하고, class속성이 아닌 id속성을 사용하는 것을 제외하곤 클래스 선택자와 매우 유사합니다. 따라서 [예제4] 역시 [예제3]과 같은 결과가 나옵니다. 하지만 이 둘 사이엔 어떤 문자를 사용하느냐보다 더 중요한 차이점이 있습니다.

클래스 선택자를 써야 할까요? ID선택자를 써야 할까요?

비슷하게 사용되는 두 선택자 중 어떤 것을 사용해야 할지 고민에 빠지는 경우가 생길 수 있습니다. 그럴땐 다음 네 가지를 고려해보면 됩니다.

  1. 한 페이지 내에서 여러 번 반복될 필요가 있는 스타일은 클래스 선택자를 사용하고, 단 한번 유일하게 적용될 스타일은 ID선택자를 사용하는 것이 좋습니다. 이는 다음과 같은 두 속성의 차이 때문입니다.

    • class속성은 어떤 분류 안에 포함된 요소의 특성을 정의하는 데 사용됩니다.
    • id속성은 어떤 요소에 대해 유일한 특성을 정의합니다. (HTML 문서에서 특정 id속성값은 오직 하나만 있어야 합니다.)
  2. 클래스 선택자는 글자색이나 글자 굵기 등 나중에 다른 곳에도 적용할 수 있는 스타일을 지정하고, ID선택자는 웹 문서 안에서 요소의 배치 방법을 지정할 때 자주 사용합니다.

  3. class 속성은 속성값을 두 개 이상 가질 수 있습니다. 그래서 클래스 선택자를 사용하면 한 태그 내에서도 여러종류의 스타일 규칙을 적용할 수 있습니다.

  4. ID선택자의 우선순위가 클래스 선택자의 우선순위보다 높습니다. 우선으로 적용되어야 할 스타일을 ID선택자를 사용하여 정의하는 것이 좋습니다. (선택자 우선순위는 뒤에서 다시 언급합니다.)

2.5 복합 선택자(Combinator)

복합 선택자는 두 개 이상의 선택자 요소가 모인 선택자입니다. (이는 꼭 태그 선택자 간의 결합이 아니어도 됩니다.)

하위 선택자(Descendant Combinator)와 자식 선택자(Child Combinator)

패턴의미CSS Level지원하지 않는
브라우저
E FE 요소의 자손인 F 요소를 선택합니다.1-
E>FE 요소의 자식인 F 요소를 선택합니다.2IE6
/* CSS */
/* 하위 선택자 */
section ul { border: 1px dotted black; }

/* 자식 선택자 */
section>ul { border: 1px dotted black; }  

[예제 5] 하위 선택자와 자식 선택자

태그들이 포함 관계를 가질 때 포함하는 요소를 부모 요소, 포함되는 요소를 자식 요소라고 합니다. 하위 선택자는 부모 요소에 포함된 '모든' 하위 요소에 스타일을 적용합니다. 하지만, 자식 선택자는 부모의 바로 아래 자식 요소에만 적용합니다. [예제 5]를 통해 선택되는 요소는 다음과 같습니다.

[그림 2] 하위 선택자
[그림 3] 자식 선택자

인접 형제 선택자(Adjacent Sibling Combinator)와 일반 형제 선택자(General Sibling Combinator)

패턴의미CSS Level지원하지 않는
브라우저
E+FE 요소를 뒤따르는 F 요소를 선택합니다.
(E와 F 사이에 다른 요소가 존재하면 선택하지 않습니다.)
2IE6
E~FE 요소가 앞에 존재하면 F를 선택합니다.
(E가 F보다 먼저 등장하지 않으면 선택하지 않습니다.)
3IE6
/* CSS */
/* 인접 형제 선택자 */
h1+ul { background: yellowgreen; color: darkgreen; }

/* 일반 형제 선택자 */
h1~ul { background: darkgreen; color: yellowgreen; }  

[예제 6] 인접 형제 선택자와 일반 형제 선택자

같은 부모 요소를 가지는 요소들을 형제 관계라고 부릅니다. 이 때 먼저 나오는 요소를 '형 요소', 나중에 나오는 요소를 '동생 요소'라고 합니다. 먼저 나온다는 것은 html문서에 먼저 쓰여지는 것을 말합니다.

인접 형제 선택자는 형제 중 첫번째 동생 요소가 조건을 충족시킬 때에만 스타일을 적용합니다. 하지만 일반 형제 선택자는 조건을 충족하는 모든 동생 요소에 스타일을 적용합니다. 두 선택자 모두 형 요소에는 적용되지 않습니다. [예제 6]을 통해 선택되는 요소는 다음과 같습니다.

[그림 4] 인접 형제 선택자
[그림 5] 일반 형제 선택자

2.6 속성 선택자(Attribute Selectors)

위에서 살펴본 선택자들은 태그나 클래스 이름, ID이름만 알면 그대로 스타일을 적용할 수 있습니다. 하지만 이제 살펴볼 속성 선택자는 클래스 속성이나 ID속성과 같이 대표적인 속성이 아닌 태그 안의 특정 속성들에 따라 스타일을 지정합니다. 속성 값의 조건에 따라 다양한 스타일을 지정할 수 있기 때문에 활용도가 높은 스타일 지정 방식입니다.

패턴의미CSS Level지원하지 않는
브라우저
E[attr]'attr' 속성이 포함된 요소 E를 선택합니다.2IE6
E[attr="val"]'attr' 속성의 값이 정확하게 'val'과 일치하는 요소 E를 선택합니다.2IE6
E[attr~="val"]'attr' 속성의 값에 'val'이 포함되는 요소를 선택합니다.
(공백으로 분리된 값이 일치해야 합니다.)
2IE6
E[attr^="val"]'attr' 속성의 값이 'val'으로 시작하는 요소를 선택합니다.3IE6
E[attr$="val"]'attr' 속성의 값이 'val'으로 끝나는 요소를 선택합니다.3IE6
E[attr*="val"]'attr' 속성의 값에 'val'이 포함되는 요소를 선택합니다.3IE6
E[attr|="val"]'attr' 속성의 값이 정확하게 'val' 이거나
'val-' 으로 시작되는 요소 E를 선택합니다.
2IE6
/* CSS */
/* E[attr]형식 */
a[href] { background: yellowgreen; color: black; }

/* E[attr="val"]형식 */
input[type="text"] { width: 150px; border: 1px solid #000; }

/* E[attr$="val"]형식 */
a[href$=".xls"] { background: darkgreen; }

<!-- HTML -->  
<a href="one.html">E[attr]형식</a>  
<input type="text" name="name">  
<a href="one.xls">E[attr$="val"]형식</a>  

[예제 7] 속성 선택자

속성 선택자는 모두 앞쪽에 태그명과 대괄호 "[]"사이에 속성에 관련된 내용을 넣어서 선택합니다. E[attr="val"]형식은 속성과 속성값이 완벽하게 일치하는 경우에 선택됩니다. 하지만 E[attr~="val"]선택자는 띄어쓰기를 통해 여러개 올 수 있는 속성값 중 하나만 일치해도 선택합니다.

또한 E[attr^="val"]형식은 "val"으로 시작하는 속성값을 선택합니다. 예를 들어 웹 문서에서 외부로 연결되는 링크가 있을 경우 http://로 시작하는지 확인하기 위해 이 선택자를 쓸 수 있습니다. 반대로 E[attr$="val"]형식은 "val"으로 끝나는 속성값을 선택합니다. 이 선택자는 예제6에 나온 것 처럼 어떤 파일이 링크될 경우, 그 파일의 확장자를 확인하기 위해 쓸 수 있습니다.

2.7 가상 클래스 선택자(Pseudo-Classes)

가상 클래스는 웹 문서의 소스에는 실제로 존재하지 않지만 필요에 의해 임의로 가상의 선택자를 지정하여 사용하는 것을 말합니다.

링크 선택자(The link pseudo-classes)와 동적 선택자(The user action pseudo-classes)

패턴의미CSS Level지원하지 않는
브라우저
E::link방문하지 않은 링크 E를 선택합니다.1-
E::visited방문한 링크 E를 선택합니다.1-
E::activeE 요소에 마우스 클릭 또는 키보드 엔터가 눌린 동안 E를 선택합니다.1, 2-
E::hoverE 요소에 마우스가 올라가 있는 동안 E를 선택합니다.1, 2-
E::focusE 요소에 포커스가 머물러 있는 동안 E를 선택합니다.1, 2-

:link와 :visited는 문서 안의 링크와 관련된 선택자입니다. 나머지 세가지 선택자는 링크 요소뿐만 아니라 다른 요소에도 적용할 수 있습니다. :active선택자는 해당 요소가 활성화된 상태를 선택합니다. 링크요소가 선택된 경우를 예로 들 수 있습니다. :hover선택자는 마우스 포인터가 해당 요소위에 올라가 있는 상태를 선택합니다. 흔히 말하는 롤오버 효과(rollover)를 만드는 선택자입니다. 마지막 :focus선택자는 해당 요소에 초점이 맞춰있는 상태를 선택합니다. 초점이 맞춰졌다는 것은 텍스트 필드 안에 커서가 놓여진 것과 같은 상태를 말합니다.

구조적 가상 클래스 선택자(Structural pseudo-classes)

구조적 가상 클래스 선택자는 위치를 기준으로 삼습니다. 그래서 요소가 몇번째에 있느냐에 따라 스타일을 다르게 지정할 수 있게 해줍니다. 순차적으로 같은 태그의 여러 항목이 있을 경우, 메뉴 간의 스타일을 변경하거나 할 때 이 선택자들이 유용하게 쓰입니다.

패턴의미CSS Level지원하지 않는
브라우저
E::root문서의 최상위 요소(html)를 선택합니다.3IE6, 7, 8
E::nth-child(n)앞으로부터 지정된 순서와 일치하는 요소가 E 라면 선택합니다.
(E 아닌 요소의 순서가 계산에 포함)
3IE6, 7, 8
E::nth-last-child(n)뒤로부터 지정된 순서와 일치하는 요소가 E 라면 선택합니다.
(E 아닌 요소의 순서가 계산에 포함)
3IE6, 7, 8
E::nth-of-type(n)E 요소 중 앞으로부터 순서가 일치하는 E 요소를 선택합니다.
(E 요소의 순서만 계산에 포함)
3IE6, 7, 8
E::nth-last-of-type(n)E 요소 중 끝으로부터 순서가 일치하는 E 요소를 선택합니다.
(E 요소의 순서만 계산에 포함)
3IE6, 7, 8
E::first-child첫 번째 등장하는 요소가 E 라면 선택합니다.
(E 아닌 요소의 순서가 계산에 포함)
2IE6
E::last-child마지막에 등장하는 요소가 E 라면 선택합니다.
(E 아닌 요소의 순서가 계산에 포함)
3IE6, 7, 8
E::first-of-typeE 요소 중 첫 번째 E를 선택합니다.(E 요소의 순서만 계산에 포함)3IE6, 7, 8
E::last-of-typeE 요소 중 마지막 E를 선택합니다.(E 요소의 순서만 계산에 포함)3IE6, 7, 8
E::only-childE 요소가 유일한 자식이면 선택합니다.
(E 아닌 요소가 하나라도 포함되면 선택하지 않습니다.)
3IE6, 7, 8
E::only-of-typeE 요소가 유일한 타입이면 선택합니다.
(E 아닌 요소가 포함되어도 E 타입이 유일하면 선택합니다.)
3IE6, 7, 8
E::empty텍스트 및 공백을 포함하여 자식 요소가 없는 E를 선택합니다.3IE6, 7, 8

그 외의 선택자

언어 선택자(language pseudo-classes)

패턴의미CSS Level지원하지 않는
브라우저
E::lang(ko)HTML lang 속성의 값이 'ko'으로 지정된 요소를 선택합니다.2IE6, 7

부정 선택자(Negation pseudo-class)

패턴의미CSS Level지원하지 않는
브라우저
E::not(S)S가 아닌 E 요소를 선택합니다.3IE6, 7, 8

목적 선택자(The target pseudo-class)

패턴의미CSS Level지원하지 않는
브라우저
E::targetE의 URI가 요청되면 선택합니다.
(따라서 E는 ID가 지정되어 있어야 합니다.)
3IE6, 7, 8

UI요소 상태 선택자(The UI element states pseudo-classes)

패턴의미CSS Level지원하지 않는
브라우저
E::enabled사용 가능한 폼 콘트롤(input, textarea, select, button) E를 선택합니다.3IE6, 7, 8
E::disabled사용 불가능한 폼 콘트롤(input, textarea, select, button) E를 선택합니다.3IE6, 7, 8
E::checked선택된 폼 콘트롤(input checked="checked")을 선택합니다.3IE6, 7, 8

가상 엘리먼트 선택자(Pseudo-Elements)

패턴의미CSS Level지원하지 않는
브라우저
E::first-lineE 요소의 첫 번째 라인을 선택합니다.1IE6
E::first-letterE 요소의 첫 번째 문자를 선택합니다.1IE6
E::beforeE 요소의 시작 지점에 생성된 요소를 선택합니다.2IE6, 7
E::afterE 요소의 끝 지점에 생성된 요소를 선택합니다.2IE6, 7

3. 선택자(Selector) 우선순위

스타일 시트는 다음과 같은 3개의 CSS원천 소스(Original Source)를 가질 수 있습니다.

  • 제작자(author) 원천 소스 : 웹 사이트 제작자가 지정하는 자신의 페이지 스타일
  • 사용자(user) 원천 소스 : 사용자가 직접 정하는 자신이 사용할 스타일
  • 사용자 도구(user agent) 원천 소스 : 웹 브라우저 자체에 지정된 기본 스타일

스타일을 적용하는데는 다양한 방법이 있으며 동시에 여러가지 방법을 사용하게 되면 스타일이 충돌할 수 있습니다. 그렇기 때문에 각 원천 소스간은 물론, 선택자 간의 우선순위를 알아야 합니다. 다음의 우선순위 규칙을 통해 원하는 스타일을 정확히 적용할 수 있습니다.

1) 원천 소스 우선 순위

!important 선언을 한 사용자 스타일 > !important 선언을 한 제작자 스타일 > 제작자 스타일 > 사용자 스타일 > 사용자 도구 선언 (브라우저 자체의 선언)

2) CSS 명시도(Specificity) 계산법

!important > id [ 100 ] > class [ 10 ] > tag [ 1 ] > * [ 0 ]

!important선언을 사용한 형식이 가장 우선 순위가 높습니다. 그래서 다른 선언들을 덮어버릴 수 있기 때문에 꼭 필요한 곳에만 사용해야 합니다.

이를 제외한 나머지 선택자는 대괄호 "[]"안에 있는 숫자를 각각의 점수로 부여하여 우선순위를 계산합니다.

  • ID 선택자의 갯수를 세어서 개당 100 으로 계산합니다. (= a)
  • 클래스 선택자의 갯수를 세어서 개당 10 으로 계산합니다. (= b)
  • 태그 선택자의 갯수를 세어서 개당 1 로 계산합니다. (= c)
  • 공용 선택자는 모두 0으로 계산합니다. (= d)
  • 가상 엘리먼트는 무시합니다.

→ a + b + c + d의 값이 높은 순서대로 스타일을 적용하는 우선순위를 가지게 됩니다. 다음의 예를 봅시다.

초록색으로 표시된 태그 선택자 3개와 빨간색으로 표시된 클래스 선택자 1개로 이루어진 스타일 규칙입니다. 우선순위 규칙에 따라 b의 값은 10×1=10이 되고, c의 값은 1×3=3이 됩니다. 따라서 이 스타일 규칙의 우선순위 값은 13입니다.

초록색으로 표시된 태그 선택자 1개와 파란색으로 표시된 ID 선택자 1개로 이루어진 스타일 규칙입니다. 우선순위 규칙에 따라 a의 값이 100×1=100이 되고, c의 값은 1×1=1이 됩니다. 따라서 이 스타일 규칙의 우선순위 값은 101입니다.

이 두 스타일 규칙이 하나의 html태그에 겹치는 가능한 다음과 같은 경우가 있다고 하면, 우선순위 값이 101인 아래쪽의 스타일 규칙이 적용됩니다.

<ul>  
....
</ul>  
<ol>  
    <li class="num" id="selector1"></li>  /* 아래쪽 스타일 규칙이 적용되는 부분 */
</ol>  

3) 마지막에 지정된 스타일을 우선 적용합니다.

스타일 우선순위가 같거나, 계산 방법이 없는 경우 마지막에 지정된 스타일이 우선으로 적용됩니다. 예를 들어 자손 선택자와 자식 선택자가 부딪힐 경우, 우선순위 계산법이 없으므로 두 선택자 중 마지막에 지정된 스타일이 적용됩니다.

맺음말

지금까지 웹 표준의 '표현'을 담당하는 CSS의 선택자에 대해 알아보았습니다. CSS에서 Cascading은 그 이름처럼 중요한 개념입니다. 단계적으로 적용되는 이러한 속성 때문에 같은 요소에 여러 가지 스타일이 겹쳐지는 경우가 자주 생기게 됩니다. 그러다보니 선택자를 통해 적절한 우선순위를 부여해주는 것이 중요합니다.

이번 CSS선택자 공부를 통해, 컨텐츠의 의미를 부각시키는 CSS의 탄탄한 체계를 알 수 있었습니다. 또한 CSS3에 들어 제공된 수많은 선택자들을 보고, 웹 상에서 가능한 것이 점점 많아진다는 것이 실감되었습니다. 웹 표준과 함께 CSS에도 더욱 관심을 기울이는 개발자가 되어야겠다는 생각이 듭니다.

읽어주셔서 감사합니다.

참고도서 및 사이트


출처 : http://www.nextree.co.kr/p8468/  by: 넥스트리소프트


0. 시작하기에 앞서...


가상 메모리에 대한 문서를 작성하기 전에, 
가상 메모리를 이해하는데, 필요한 선행 지식 중 하나인 페이지 테이블에 대해 정리한다.

이 문서는 Wikipedia의 문서를 번역하며, 개인적인 코멘트를 더해 작성되었다.


1. 페이지 테이블

가상 메모리를 사용하는 운영 체제에서 개별 프로세스는 자신만의(고유의) 가상 주소 공간을 가지고 있다.

32비트 프로세스는 0x00000000 ~0xFFFFFFFF까지 표현될 수 있기에 4GB 크기의 주소 공간을,
64비트 프로세스는 0x000000000000000 ~ 0xFFFFFFFFFFFFFFFF까지 표현될 수 있기에 16EB 크기의 주소 공간을 가진다.

각 프로세스들의 가상 메모리는 물리 메모리의 각기 다른 영역에 분산되어 로드될 수 있거나,
page-out 되어 paging file(하드 디스크에 존재하는)에만 저장될 수 있다.

프로세스가 특정 메모리에 접근하려 하면, 운영체제는 프로세스의 가상 주소를 시스템의 물리 메모리 주소로 변환해 주어야 한다.

페이지 테이블은 가상 주소와 물리 메모리 주소의 매핑 테이블이며, 개별 매핑 데이터는 Page-Table-Entry(PTE)라고 한다.

페이지 테이블은 프로세스마다 하나씩 존재하게 되며, 메인 메모리 (RAM)에 상주하게 된다.
즉, 많은 프로세스가 구동될 수록, 페이지 테이블로 인한 메인 메모리 사용이 커짐을 의미한다.

참고로, 가상 메모리와 물리 메모리의 관계는 아래 그림과 같이 표현될 수 있다.


2. Virtual address -> Physical address 변환 과정

CPU의 MMU(Memory Management Unit)는 최근에 맵핑된 페이지 테이블의 정보들을 TLB라는 연관 캐쉬에 저장한다.
(TLB : Translation Lookaside Buffer)

TLB는 자주 쓰는 페이지 테이블의 주소를 저장해 둠으로써, translation의 속도를 향상시켜 주는 역할을 한다.

1) 가상 주소가 물리 메모리 주소로 변환되어야 할 때, 먼저 TLB를 검색한다.
TLB에서 검색이 성공하면 (TLB hit), 즉시 물리 메모리 주소를 반환하며, 프로세스는 해당 주소로 접근이 가능하다.

2) 만약, TLB에서 검색이 실패하면 (TLB miss), 통상적으로 핸들러는 해당 가상 주소에 맵핑된 물리 메모리 주소가 있는지
페이지 테이블을 검색하게 된다. (Page walk)

3) 페이지 테이블에서 일치하는 맵핑 데이터를 찾았다면, 해당 정보를 TLB에 업데이트하고,
1) 번 과정으로 돌아가 해당 가상 주소의 물리 메모리 주소로의 요청을 재개하게 된다.


3) 과정에서 페이지 테이블에서도 적절한 물리 메모리 주소를 찾기 못하게 되는 경우가 있는데, 이는 두 가지 이유에서 비롯된다.

첫번째는 가상 메모리 주소 자체가 유효하지 않은 경우이다.
이 경우, 운영체제는 해당 가상 주소 접근을 요청한 프로세스에게 segmentation fault를 발생시키게 된다.

두번째가 일반적인 경우인데, 해당 가상 메모리 주소가 물리 메모리에 존재하지 않는 경우이다.
이 경우, 해당 page가 다른 메모리 접근 요청에 의해 물리 메모리 공간이 부족해져 page-out 된 상황이다.

Page가 page-out되면, 하드디스크의 보조 저장소로 옮겨지게 되며, 
이 저장소가 우리가 알고 있는 paging file 또는 swap file이다.

다시 돌아가서, 프로세스가 접근하려는 가상 메모리 주소가 물리 메모리에서 page-out 된 상황이라면,
운영체제는 page fault 를 발생시키며, 아래와 같은 순서로 다시 물리 메모리로 로드시킨다.

a. 물리 메모리가 꽉 차지 않았다면(empty frame이 존재한다면), 
페이징 파일에 존재하는 데이터를 램에 존재하는 empty frame으로 로드하면서, 페이지 테이블과 TLB의 내용을 갱신한다.

b. 물리 메모리에 empty frame이 존재하지 않는다면, (즉, 여유 공간이 없다면)
램에서 empty로 변경할 페이지를 찾은 후 (이 과정에서 page replacement alogorithm이 적용된다)
페이지의 데이터가 변경되었다면, 이를 다시 paging file에 쓴 후 해당 page를 empty frame으로 변환시킨다.

그리고, 로드하려 했던 데이터를 방금 empty frame으로 만들었던 곳으로 로드하면서, 페이지 테이블과 TLB의 내용 역시 갱신한다.
이 경우 페이지 테이블이나 TBL 업데이트에는 page-out된 page에 대한 제거 과정도 포함된다.

a/b 과정을 모두 거치게 되면, 해당 가상 주소의 물리 메모리 주소로의 요청을 재개하게 된다.

지금까지의 과정을 TLB와 페이지 테이블 관점에서 정리하면, 아래 그림과 같다.

일반적인 경우엔 지금까지의 설명한 과정을 거치지만, 
공유 Memory Mapped File의 경우 아래 그림과 같이프로토타입 페이지 엔트리 테이블를 찾는 과정이 하나 더 들어가게 된다.


3. 페이지 테이블 데이터

가장 단순한 페이지 시스템은 종종 프레임 테이블과 페이지 테이블을 함께 유지한다.

프레임 테이블은 어느 프레임이 매핑되어 있는지에 대한 정보를 들고 있다.
조금 더 진보된 시스템에서는 프레임 매핑 정보 외 부가적인 정보들도 함게 포함한다.

페이지 테이블은 가상 주소의 페이지와 물리 메모리 프레임간의 매핑 정보를 들고 있다.
그리고, 다음과 같은 부가 정보들을 포함한다.
  • reference bit (accessed bit)
  • valid bit (present bit)
  • dirty bit (modified bit)
  • process ID information
1) Reference bit

Page replacement alogorithm에 사용되며, 해당 페이지에 대한 접근이 있었는지에 대해 기록한다.

2) Valid bit

하드 디스크와 같은 이차 저장 장치는 물리 메모리의 총량을 증가시키는데 사용될 수 있다.
Page 단위의 메모리는
  • 페이징 파일에서 물리 메모리로 page-in 될 수 있고,
  • 물리 메모리로부터 페이징 파일로 page-out 될 수 있다.
위 페이지 테이블의 정보 중 present bit는 이 page가 물리 메모리에 있는지, 페이징 파일에 있는지 여부를 나타내는데 사용된다.

3) Dirty bit

Dirty bit는 가상 메모리 관리 시스템의 성능을 향상시키는 데 아주 중요한 역할을 수행한다.

어떤 page가 물리 메모리로 page-in 된 이후, 내용이 전혀 달라진 게 없다면
이 page가 추후 paging file로 page-out 될 때, 달라진 게 없으므로 내용을 다시 복사하지 않아도 되게 된다.

그와 반대로 page-in 된 이후 내용이 달라진 것이 있다면, page-out 될 때 반드시 해당 내용을 pagine file에 써야 할 것이다.

이 과정에서 page-out 되기까지 해당 page의 내용이 변경 되었는지를 기록하는 것이 dirty bit 이다.
만약, 이 dirty bit 이 없었다면, 모든 page-out 과정에서 page data copy가 발생할 것이고, 이는 불필요한 성능 하락을 발생시킨다.

4) Process ID information

가상 메모리 관리 시스템은 어떤 페이지가 어느 프로세스와 연관이 있는지 알고 있어야 한다.

두 개의 프로세스가 각기 다른 목적을 위해 동일한 주소의 가상 메모리에 접근한다고 가정해 보자.
(가상 주소는 프로세스별로 독립적이므로, 주소가 같다고 해서 같은 메모리를 가리키는 것은 아니다)

페이지 테이블은 두 프로세스가 요청한 가상 메모리 주소에 대해 정보를 각기 저장시킬 수 있어야 한다.

이를 구분하기 위해 페이지 테이블은 두 개의 정보를 기록할 때 각기 다른 identifier를 부여하거나,
해당 process id를 기록해 두어야 한다.

이러한 방식을 대체하고자 하는 방식이 페이지 테이블을 프로세스별로 두는 것이다.
최근의 OS는 이 방식을 더 많이 사용한다.
즉, 프로세스별 페이지 테이블이 존재하고, 이들은 메인 메모리(RAM)에 상주하는 것이다.


4. 페이지 테이블의 종류

페이지 테이블은 다음과 같은 종류가 있다고 한다.
  • Inverted
  • Multi-level
  • Virtualized
  • Nested
이 중 x86 이 사용하는 것은 Multi-level 방식이라고 한다.

만약 Single-level 즉, 하나의 page table로 4GB의 주소 공간을 표현하기 위해선 2 ^ 20개의 PTE가 필요하다.
(4GB / 4KB(1 page size) = 2 ^ 32 / 2 ^ 12 = 2 ^ 20)

2 ^ 20개면 1024 * 1024개의 PTE 정보를 가져야 하는데, 
이러면 페이지 테이블의 크기가 너무 커져서, 2 or 3 level paging을 하게 된다.

Page directory와 page table로 나누어, 이들의 관계로 전체적인 크기를 감소시키는 것이다.

음... 더 이상 자세한 내용은 wikipedia 페이지를 참고하기 바란다. (정리 귀차늠 -_-)

웹질 하다가 페이지 테이블 종류와 설명에 대한 유투브를 찾아냈다.


출처  : http://egloos.zum.com/sweeper/v/2988646 by 수까락


'컴퓨터에 관한 지식' 카테고리의 다른 글

세마포어와 뮤텍스의 차이  (0) 2017.05.29
객체지향 개발 5대 원리: SOLID  (0) 2017.05.29

+ Recent posts