레이블이 BSD인 게시물을 표시합니다. 모든 게시물 표시
레이블이 BSD인 게시물을 표시합니다. 모든 게시물 표시

2012-09-14

FreeBSD] ab (아파치 응답속도를 측정하는 툴)


ab
ab는 “Apache HTTP server Benchmarking tool”의 약어로서  아파치서버의 응답속도를 측정하는 밴치마킹툴입니다.
ab라는 툴을 이용하여 아파치의 응답속도를 테스트하고 그 결과를 다양한 방면으로 확인할 수 있습니다.  

사용형식
ab [ -k ] [ -i ] [ -n 요청수 ] [ -t 시간제한 ] [ -c 동시접속 ] [ -p POST file ] [ -A 인증 유저이름:패스워드 ] [ -P 프락시인증 유저이름:패스워드 ] [ -H Custom header ] [ -C Cookie name=value ] [ -T content-type ] [ -v verbosity ] ] [ -w HTML 출력 ] ] [ -x 속성 ] ] [ -y  속성 ] ] [ -z  속성 ] [http://]서버이름[:port]/path 

ab [ -V ] [ -h ]

사용예 #1
V를 사용하시면 설치되어 있는 ab의 버전을 확인하실 수있습니다. 아래 결과는 현재 필자가 사용하고 있는 ab의 버전이 2.0.40이라는 것을 표시하고 있습니다. 
[root@host3 bin]# ab -VThis is ApacheBench, Version 2.0.40-dev <$Revision: 1.116 $> apache-2.0
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 1998-2002 The Apache Software Foundation, http://www.apache.org/
[root@host3 bin]#
사 용예 #2
수퍼유저코리아(www.superuser.co.kr)의 응답속도를 측정한 것입니다. 참고로 사이트URL의 마지막에는 반드시 "/"가 들어가야함에 주의하시기 바랍니다.  여기서 사용한 옵션 -n은 측정을 위한 웹페이지 요청수를 의미합니다. 즉 "-n 1"이라고 한 것은 지정한 URL을 한번의 요청만으로 결과를 표시한다는 의미입니다.
[root@host3 bin]# ab -n 1 http://www.superuser.co.kr/
This is ApacheBench, Version 2.0.40-dev <$Revision: 1.116 $> apache-2.0
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 1998-2002 The Apache Software Foundation, http://www.apache.org/
Benchmarking www.superuser.co.kr (be patient).....done

Server Software:        Apache/2.0
Server Hostname:        www.superuser.co.kr
Server Port:            80
Document Path:          /
Document Length:        458 bytes
Concurrency Level:      1
Time taken for tests:   1.499567 seconds
Complete requests:      1
Failed requests:        0
Write errors:           0
Total transferred:      700 bytes
HTML transferred:       458 bytes
Requests per second:    0.67 [#/sec] (mean)
Time per request:       1499.567 [ms] (mean)
Time per request:       1499.567 [ms] (mean, across all concurrent requests)
Transfer rate:          0.00 [Kbytes/sec] received
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       17   17   0.0     17      17
Processing:  1482 1482   0.0   1482    1482
Waiting:     1481 1481   0.0   1481    1481
Total:       1499 1499   0.0   1499    1499
[root@host3 bin]#
사 용예 #3
다음과 같이 -c옵션을 사용하면 한번에 수행할 다중 요구수를 지정할 수 있습니다.  지정하지 않는다면 기본값은 1이 됩니다.  테스트시에 c 30이라고 주었으며, 결과를 보시면 concurrency Level30이라는 것을 보실 수 있을 것입니다. 즉, 동시에 다중세션을 테스트한 것이며 그 결과를 확인 할 수 있습니다. 결과값의 분석은 앞에 설명된 내용과 비교하면서 보시기 바랍니다.
[root@host3 bin]# ab -c 30 http://www.yahoo.com/
This is ApacheBench, Version 2.0.40-dev <$Revision: 1.116 $> apache-2.0
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 1998-2002 The Apache Software Foundation, http://www.apache.org/
Benchmarking www.yahoo.com (be patient).....done

Server Software:       
Server Hostname:        www.yahoo.com
Server Port:            80
Document Path:          /
Document Length:        32247 bytes
Concurrency Level:      30
Time taken for tests:   1.75287 seconds
Complete requests:      1
Failed requests:        0
Write errors:           0
Total transferred:      32600 bytes
HTML transferred:       32247 bytes
Requests per second:    0.93 [#/sec] (mean)
Time per request:       32258.610 [ms] (mean)
Time per request:       1075.287 [ms] (mean, across all concurrent requests)
Transfer rate:          28.83 [Kbytes/sec] received
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:      208  208   0.0    208     208
Processing:   866  866   0.0    866     866
Waiting:      219  219   0.0    219     219
Total:       1074 1074   0.0   1074    1074
root@host3 bin]#

저작권:수퍼유저코리아(www.superuser.co.kr), 무단 재배포및 복사를 금합니다.

FreeBSD] Using Subversion for Collaborative Development-- subversion 설치






혹시 몰라서 내용을 아래 부분에 첨부 합니다.
이 글은 bsdguides.org 의 내용을 그대로 옮긴 부분입니다.


========================================
Print View
Using Subversion for Collaborative Development
Updated: 07/15/2005

General Information
Subversion (SVN) is an alternative to using Concurrent Version System (CVS) for collaborative development, though it has other uses if you develop on more than one machine and wish to keep all your work in a central location.  This guide will show you how to setup Subversion with Webaccess via the Apache2 mod_dav svn module.  If you already use apache 1.3 you can continue to use that, just change the port that apache2 listens on in its httpd.conf file.

Subversion Book is an excellent resource for information outside the scope of this guide.
Requirements
  1. Local root access on the box or be able to su to root.
  2. A SSH client such as puTTy or SecureCRT (if you are setting it up remotely).
  3. A plain text editor, I prefer nano
Installation
We have to start out by building apache2.  Because we are building it with the intention of using Subversion with it, we must build it with Berkeley DB (sleepycat) support, as the Subversion filesystem is actually built as a sleepycat database.  It is this that allows for the versioning of files.
#
#
cd /usr/ports/www/apache2
make install WITH_BERKELEYDB=db42
We make sure that the apache2 aprutil library is known, this file sometimes seems to get "lost"
#
#
#
ldconfig -m /usr/local/lib/apache2/
echo "/usr/local/lib/apache2" >> /etc/ld.so.conf
echo "/usr/local/lib/apache2" >> /etc/ld-elf.so.conf
Instruct the Operating System to run apache2 at startup
#echo 'apache2_enable="YES"' >> /etc/rc.conf
Now to build Subversion
#
#
cd /usr/ports/devel/subversion
make install -DWITH_MOD_DAV_SVN
Configuration
OK, subversion and apache with berkeley db support are now compiled and installed.  You have a choice of either creating a single huge repository for all of your projects, or individual repositories for each.  I will detail each now.
General Setup
Create Subversion Home folder
#mkdir -p /usr/home/svn
Create a generic repository format
#
#
#
mkdir -p /usr/home/svn/default/trunk
mkdir /usr/home/svn/default/branches
mkdir /usr/home/svn/default/tags
Copy some files will need for the web interface
#cp /usr/ports/devel/subversion/work/subversion-1.0.6/tools/xslt/* /usr/local/www/data-dist/
Note:  The path to the tools/xslt will change with versions of subversion so change the <em>subversion-1.0.6</em> to whatever it is for your version of subversion, ie subversion-1.0.7 or subversion-1.0.8 and so on.
Setup Blanket Access:  If you wish to enable htaccess style password login to the subversion repository then use this system. This is the basic access control system, which can be extended to enable per directory access control as well.
#
#
mkdir /usr/home/svn/access
touch /usr/home/svn/access/users
Create the users using the htpasswd utility
#htpasswd -mb /usr/home/svn/access/users <em>username</em> <em>password</em>
Configuring Apache2 for Blanket Access control
#nano -w /usr/local/etc/apache2/httpd.conf
Add the following to the httpd.conf file, this can be at the bottom or wherever, it will create ahttp://www.myservername.com/svn/ URL which you can then access
## SVN WebDAV Repository Setup
<Location /svn>
     DAV svn
     SVNParentPath /usr/home/svn/repos
     SVNIndexXSLT "http://www.myservername.com/svnindex.xsl"
    
     # anonymous first
     Satisfy Any
     Require valid-user
    
     # authenticating them valid ones
     AuthType Basic
     AuthName "Subversion Repositories"
     AuthUserFile /usr/home/svn/access/users
</Location>
This can also be placed inside a virtual host directive

Extending the Blanket Access control to enable Per-Directory Access control
#touch /usr/home/svn/access/control
If you are going to use a single large repository with all your projects in and you wish to allow and deny some users access to certain parts of the repository, then you can setup the control file like this.  In this example I will use users with the names of admin, manager (a project manager), commiter, client.  The access rules are inheritted, but I will demonstrate how to override an inheritted value.  If someone is not mentioned at all within the tree, then they are denied access.
[/]
admin = rw
manager = r

[/bigproject]
manager = rw
commiter = r

[/bigproject/trunk]
commiter = rw
client = r

[/bigproject/branches]
client = r

[/bigproject/trunk/manager_notes]
client =
commiter =
In this file from the very start the admin has full rights to the whole repository, and the manager can read and see all of the projects, but he has full access to the whole of the bigproject folder and the commiter can read the whole of the bigproject folder, all the development is to be kept in trunk so the commiter has full access to that, and the clients might want to be able to get the latest builds of a project, so they can read it.  They might also want access to the stable branches, so they are allowed read access to that.  Finally, the project manager has some project notes which he doesn't want anyone else to gain access to, so the client and commiter are set to empty permissions which denys them access to that folder.  You can also specify general access rights for all by using the '*' and assigning access rights to that.
Now the same again, but using per directory access control on a multiple repository system
[bigproject:/]
admin = rw
manager = rw
commiter = r

[bigproject:/trunk]
commiter = rw
client = r

[bigproject:/branches]
client = r

[bigproject:/trunk/manager_notes]
client =
commiter =
Edit the apache2 config file to use per-directory access control.  Find the Blanket Access control Location area and add the below lines just underneath the SVNIndexXSLT
# If we are using the Per-Directory Access Control then we leave this uncommented
# Access Control
AuthzSVNAccessFile /usr/home/svn/access/control
It should look like this
## SVN WebDAV Repository Setup
<Location /svn>
     DAV svn
     SVNParentPath /usr/home/svn/repos
     SVNIndexXSLT "http://www.myservername.com/svnindex.xsl"
    
     # If we are using the Per-Directory Access Control then we leave this uncommented
     # Access Control
     AuthzSVNAccessFile /usr/home/svn/access/control
    
     # anonymous first
     Satisfy Any
     Require valid-user
    
     # authenticating them valid ones
     AuthType Basic
     AuthName "Subversion Repositories"
     AuthUserFile /usr/home/svn/access/users
</Location>
Building a Single General Repository
Create our single main repository
#
#
svnadmin create /usr/home/svn/repos
svn import /usr/home/svn/default file:///usr/home/svn/repos -m "initial import"
Should you later want to divide this repository into project folders, you will need to checkout the whole repository and use the svn move, svn copy and so on commands, which can be found in the Subversion Book
Building a Multiple Project Repository
Make a new repository
#
#
#
mkdir /usr/home/svn/repos
svnadmin create /usr/home/svn/repos/<em>projectname</em>
svn import /usr/home/svn/default file:///usr/home/svn/repos/<em>projectname</em> -m "Initial Import"
Final Setup
Make sure that apache can read the svn repositories
#chown -R www:www /usr/home/svn
and make the access control and userlist readable only by apache.  All the contents are pretty much encrypted, but you don't want other shell users peeking at them, though they could get through via a php script, but this is the best way to go about it.
#
#
chmod 600 /usr/home/svn/access/control
chmod 600 /usr/home/svn/access/users
There, you now have a fully working Subversion Repository.  To checkout the contents of the trunk of a project in your repository via the command line tool
#svn checkout http://www.mydomain.com/svn/<em>projectname</em>/trunk <em>projectname</em>
this will make a folder called "projectname" in the current folder you are in when you run the command.


Once you have made changes to a project you can commit those changes by changing into the project folder then
#svn commit -m "Notes regarding the changes"
And finally to update your copy of the code from the repository, change into the project folder then
#svn update
These commands are all for the SVN Command line tool, which is installed as part of the devel/subversion port.  If you wish to use the command line tool and not create the files needed for running a repository with apache2, then use
#
#
cd /usr/ports/devel/subversion
make install clean
and skip the remaining steps.

There is also a range of clients.  The best for Windows, in my opinion, is TortoiseSVN, a comprehensive list of other clients for SVN can be found here
Author: Geffy
w00t at stealth-ninja dot co dot uk
==============================================================

FreeBSD] Subversion설치(FreeBSD6.1R)_1185418705


Subversion mini HowTo
버전 관리 프로그램인 Subversion 서버 설치에 대한 간단한 문서입니다.

환경 :
Server 환경 :
OS : FreeBSD 6.1 Released
Subversion : 1.3.0
Apache 2.2
Berkeley Database 사용

Client 환경 :
OS : 윈도우
TortoiseSVN


Requirement :
F reeBSD 6.1 / Windows family
Apache2.2
Subversion 1.3.0
TortoiseSVN
설치 작업은 반드시 root 권한으로 작업한다.

위 사항에서 FreeBSD상에서 돌아가는 것은 ports 시스템을 이용하여 설치

설치 순서 :
1. Apache2.2
2. Apcahe2.2 설정
3. Subversion 설치
4. Subversion 설정


Installation
1. Apache Installa tion
1.1. Apache2.2 설치
##cd /usr/ports/www/apache2make install WITH_MOD_DAV_SVN=yes WITH_BERKELEYDB= yes

1.2. 설정 확인
#
##
ldconfig -m /usr/local/lib 
아래 사항은 확인만 하면 됩니다.(6.1버전에서는 아래 사항은 하지 않아도 됨) echo "/usr/local/lib/apache2" >> /etc/ld.so.confecho "/usr/local/lib/apache2" >> /etc/ld-elf.so.conf

1.3. apache가 자동으로 실행되게 하기 위해 rc.conf 파일에 등록하기
#echo 'apache2 2_enable="YES"' >> /etc/rc.conf

2. Subversion Installation
2.1 Subversion 설치
##cd /usr/ports/devel/subversionmake install -DWITH_MOD_DAV_S VN

2.2 Subversion 설정(configuration)
Subversion Home folder 생성
#mkdir -p /home/svn

저장소 포맷 생성하기
###mkdir -p /home/svn/default/trunkmkdir /home/svn/default/branchesmkdir /home/svn/default/tags

웹인터페이스를 위한 파일 복사
#cp /usr/ports/devel/subversion/wo rk/subversion-1. 3. 0/tools/xslt/* /usr/local/www/data-dist/^^^^^^^^^^^^^^^^^^^^^^^^^이부분은 web doc root 입니다.

사용자 접근을 제어하기 위해 빈 파일 생성
##mkdir /home/svn/accesstouch /home/svn/access/users <- user파일을 생성하는 명령어

apache에서 제공하는 htpasswd 파일을 이용하여 사용자의 계정과 비밀번호 생성
#htpasswd -mb /home/svn/access/users username password

Apache의 설정파일인 httpd.conf 파일 수정하기
#vi /usr/local/etc/apache2 2/httpd.conf

Httpd.conf의 내용 중 일부
사용자들이 웹으로 접근하기 위해서는 아래의 문장이 들어가 있어야지 됨.
이것의 의미는 /home/svn/access/users 파일에 등록된 사용자만이 접근가능하다는 의미
/svn/sample >
DAV svn
SVNPath /home/svn/sample
AuthType Basic 
AuthName "Subversion Repository" 
AuthUserFile / home/svn/access/users 
Require valid-user
외부에서 접근할 때는 #svn checkout http://서브버전 서버IP/svn/sample 로 접근이 가능하다.

FreeBSD] subversion on FreeBSD 6.1R (간단하게 설치하기)



Subversion mini HowTo
버전 관리 프로그램인 Subversion 서버 설치에 대한 간단한 문서입니다.

환경 :
Server 환경:
OS : FreeBSD 6.1 Released
Subversion : 1.3.0
Apache 2.2
Berkeley Database 사용

Client 환경 :
OS : 윈 도우
TortoiseSVN


Requirement :
FreeBSD 6.1 / Windows family
Apache2.2
Subversion 1.3.0
TortoiseSVN
설 치 작업은 반드시 root 권한으로 작업한다.

위 사항에서 FreeBSD상에서 돌아가는 것은 ports 시스템을 이용하여 설치

설치 순서 :
1.Apache2.2
2.Apcahe2.2 설정
3.Subversion 설치
4.Subversion 설정


Installation
1. Apache Installation
1.1. Apache2.2 설치

#cd /usr/ports/www/apache2
#make install WITH_MOD_DAV_SVN=yes WITH_BERKELEYDB=yes


1.2. 설정 확인

#ldconfig -m /usr/local/lib

 아래사항은확인만하면됩니다.(6.1버전에서는아래사항은하지않아도됨)
#echo "/usr/local/lib/apache2" >> /etc/ld.so.conf
#echo "/usr/local/lib/apache2" >> /etc/ld-elf.so.conf


1.3. apache가 자동으로 실행되게 하기 위해 rc.conf 파일에 등록하기

#echo 'apache22_enable="YES"' >> /etc/rc.conf


2. Subversion Installation
2.1 Subversion 설치

#cd /usr/ports/devel/subversion
#make install -DWITH_MOD_DAV_SVN


2.2 Subversion 설정(configuration)
   Subversion Home folder 생 성
 
   #mkdir -p /home/svn
 
 
   저장소 포맷 생성하기
 
   #mkdir -p /home/svn/default/trunk
   #mkdir /home/svn/default/branches
   #mkdir /home/svn/default/tags
 
 
   웹인터페이스를 위한 파일 복사
 
 
   #cp /usr/ports/devel/subversion/work/subversion-1.3.0/tools/xslt/*
   /usr/local/www/data-dist/
   ^^^^^^^^^^^^^^^^^^^^^^^^^이부분은 web doc root 입니다.
 
 
   사용자 접근을 제어하기 위해 빈 파일 생성
 
   #mkdir /home/svn/access
   #touch /home/svn/access/users <- user파일을생성하는명령어
 
 
   apache에서 제공하는 htpasswd 파일을 이용하여 사용자의 계정과 비밀번호 생성
 
   #htpasswd -mb /home/svn/access/users username password
 
 
   Apache의 설정파일인 httpd.conf 파일 수정하기
 
   #vi /usr/local/etc/apache22/httpd.conf
 
 
   Httpd.conf의 내용 중 일부
   사용자들이 웹으로 접근하기 위해서는 아래의 문장이 들어가 있어야지 됨.
   이것의 의미는 /home/svn/access/users 파 일에 등록된 사용자만이 접근가능하다는 의미
             <Location /svn/sample>DAV svnSVNPath /home/svn/sampleAuthTypeBasicAuthName"Subversion Repository"AuthUserFile /home/svn/access/users  Requirevalid-user</Location>
           
 
 
 
   외부에서 접근할 때는 #svn checkout http://서브버전 서버IP/svn/sample 로 접근이 가능하다.


2012-09-13

FreeBSD] Subversion + Apache on FreeBSD 간단한 설치 가이드



이 글의 출처는 http://www.xinublog.com/198 입 니다.
! 아래 설치 가이드는 Berkeley DB를 사용하지 않는 것을 전제로 하고 있습니다.
! Apache2.x대를 권장합니다.

1. 먼저 아파치를 설치한다.
# cd /usr/ports/www/apache2
# make install WITH_MOD_DAV_SVN=yes

/usr /local/etc/apache22/httpd.conf에 아래 설정을 확인 및 추가합니다.
          LoadModule dav_module         modules/mod_dav.so

          LoadModule dav_svn_module     modules/mod_dav_svn.so
          

          <Location /svn/sample>

            DAV svn

            SVNPath /home/svn/sample

          </Location>
          

2. Subversion을 설치한다.
# cd /usr/ports/devel/subversion
# make install -DWITH_MOD_DAV_SVN WITHOUT_BDB=yes

http://(Subversion 과 Apache를 설치한 IP주소 또는 도메인)/svn/sample 로 접속을 합니다.
          Revision 0: /

          

          --------------------------------------------------------------------------------

          Powered by Subversion version 1.0.0.
          

FreeBSD]Bash 스크립팅 가이드2



3장. 종료와 종료 상태(Exit and Exit Status)

 
사람들은 본쉘의 어두운 면을 모두 사용한다.
 Chet Ramey
exit 명령어는 C 프로그램에서처럼 스크립트를 끝낼 때 씁니다. 또한, 스크립트의 부모 프로세스에게 어떤 값을 돌려 줄 수도 있습니다.
모든 명령어는 종료 상태( exit status (가끔은 리턴 상태( return status )라고도 하는)를 리턴합니다. 명령어가 성공시에는 0을 리턴하고 실패시에는 에러 코드로 해석될 수 있는 non-zero를 리턴합니다. 예외가 있기는 하지만, 유닉스 관례를 잘 따르는 명령어, 프로그램, 유틸리티는 성공했을 때 0을 리턴합니다.
비슷하게, 스크립트의 함수나 스크립트 자신도 종료 상태를 리턴합니다. 스크립트 함수나 스크립트에서 가장 마지막에 실행된 명령어가 종료 상태를 결정합니다. 스크립트에서 exit nnn 이라고 하면 nnn이라는 종료 상태를 쉘에게 전달해 줍니다(nnn은 0에서255 사이의 십진수여야 합니다).
참고: 매개변수 없이 그냥 exit로 끝났을 경우에는, 마지막에 실행된 명령어(exit 자신은 빼고)의 종료 상태가 스크립트의 종료 상태가 됩니다.
$? 는 제일 마지막 명령어의 종료 상태를 보여줍니다. 함수가 리턴한 다음에 $?라고 하면 함수의 마지막 명령어의 종료 상태를 알려줍니다. bash에서는 이렇게 해서 함수의 "반환값"을 돌려 줍니다. 스크립트가 종료한 다음에는 명령어줄에서 $?로 스크립트 마지막 명령어의 종료 상태를 알 수가 있는데 관습적으로 0은 성공을 나타내고 1에서 255까지의 숫자는 에러를 나타냅니다.
예 3-1. 종료/종료 상태
          #!/bin/bash echo hello echo $? # 명령어가 성공했기 때문에 종료 상태 0이 리턴됨. lskdf # 알수없는 명령어. echo $? # 0이 아닌 종료 상태가 리턴됨. echo exit 113 # 쉘에게 113을 리턴함. # 확인해 보려면 이 스크립트가 종료된 다음에 "echo $?"라고 쳐 보세요. # 관습적으로 'exit 0'은 성공을 의미합니다. # 0이 아닌 값은 에러나 예외상황을 나타냅니다.
          
$? 는 스크립트에서 실행시키 명령어의 결과를 확인하는데 특별히 유용하게 쓰입니다(예 12-8 와 예 12-13 참고).
참고: 논리적 "부정" 한정어(qualifier)인 ! 는 테스트나 명령어의 결과를 반대로 바꿔서 종료 상태에 영향을 미칩니다.
예 3-2. !으로 조건을 부정하기
          true # 쉘 내장명령어인 "true". echo "\"true\"의 종료 상태 = $?" # 0 ! true echo "\"! true\"의 종료 상태 = $?" # 1 # 조심할 점은 "!"을 쓸 때, 빈 칸이 있어야 된다는 것입니다. # 그냥 !true 라고 쓰면 "command not found" 에러가 납니다. # Thanks, S.C.
          
경고
몇몇 종료 상태 코드들은 예약돼 있기 때문에 사용자가 스크립트에서 마음대로 쓰면 안 됩니다.

4장. 특수 문자

쉘 스크립트에서 쓰이는 특수 문자들
#
주석. #으로 시작하는 줄(#!만 빼고)은 주석입니다.
          # 이 줄은 주석입니다.
          
명령어 끝에 주석이 나올 수도 있습니다.
          echo "뒤에 주석이 나옵니다." # 주석이 여기에.
          
줄 첫부분에 나오는 공백문자뒤에도 주석을 쓸 수 있습니다.
           # 이 주석 앞에 탭이 있습니다.
          
경고
한 줄에서 주석뒤에 명령어가 올 수는 없습니다. 주석과 "실제 코드"를 구분할 방법이 없기 때문에 다른 명령어는 새로운 줄에 쓰세요.
참고: 당연한 이야기지만, echo 문에서 이스케이프된 #은 주석의 시작을 나타내지 않습니다. 비슷하게 몇몇 매개변수 치환이나 산술 상수 확장에 나오는 #도 주석을 나타내지 않습니다.
          echo "이 # 은 주석의 시작이 아닙니다." echo '이 # 은 주석의 시작이 아닙니다.' echo 이 \# 은 주석의 시작이 아닙니다. echo 이 # 은 주석의 시작을 나타냅니다. echo ${PATH#*:} # 매개변수 치환으로, 주석이 아니죠. echo $(( 2#101011 )) # 진법 변환, 주석이 아닙니다. # Thanks, S.C.
          
표 준 쿼우팅(quoting)과 이스케이프(escape) 문자들인 (" ' \) 들은 # 을 이스케이프 시킬 수 있습니다.
몇몇 패턴 매칭 연산자도 #을 사용합니다.
;
명령어 구분자. [세미콜론] 두 개 이상의 명령어를 한 줄에서 같이 쓸 수 있게 해줍니다.
          echo hello; echo there
          
";"는 가끔 이스케이프 시킬 필요가 있습니다.
;;
case 옵션 종료자. [이중 세미콜론]
          case "$variable" in abc) echo "$variable = abc" ;; xyz) echo "$variable = xyz" ;; esac
          
.
"점"(dot) 명령어. [마침표] source 명령어와 동일합니다(예 11-14 참고). 이 명령어는 bash 내장 명령(builtin)입니다.
"점"(dot)이 정규 표현식(reqular expression)으로 해석될 때는, 한 개의 문자와 일치됩니다.
또다른 문맥에서는 그냥 ls 라고 쳤을 때, 보이지 않는 "숨김" 파일을 나타내는 파일명 접두어로도 쓰입니다.
          bash$ touch .hidden-file bash$ ls -l total 10 -rw-r--r-- 1 bozo 4034 Jul 18 22:04 data1.addressbook -rw-r--r-- 1 bozo 4602 May 25 13:58 data1.addressbook.bak -rw-r--r-- 1 bozo 877 Dec 17 2000 employment.addressbook bash$ ls -al total 14 drwxrwxr-x 2 bozo bozo 1024 Aug 29 20:54 ./ drwx------ 52 bozo bozo 3072 Aug 29 20:51 ../ -rw-r--r-- 1 bozo bozo 4034 Jul 18 22:04 data1.addressbook -rw-r--r-- 1 bozo bozo 4602 May 25 13:58 data1.addressbook.bak -rw-r--r-- 1 bozo bozo 877 Dec 17 2000 employment.addressbook -rw-rw-r-- 1 bozo bozo 0 Aug 29 20:54 .hidden-file
          
"
부분 쿼우팅(partial quoting). [이중 쿼우트] "문자열" 이라고 하면 쉘이 문자열에 들어 있는 거의 대부분의 특수 문자를 해석하지 못하도록 막아줍니다. 6장을 참고하세요.
'
완전 쿼우팅(full quoting). [단일 쿼우트] '문자열' 이라고 하면 쉘이 문자열에 들어 있는 모든 특수 문자를 해석하지 못하도록 막아줍니다. "보다 더 강한 형태의 쿼우팅입니다. 6장을 참고하세요.
,
콤마 연산자. 콤마 연산자 는 연속적인 산술 연산을 하려고 할 때 쓰입니다. 모든 계산이 이루어진뒤, 마지막에 계산된 결과만 리턴됩니다.
          let "t2 = ((a = 9, 15 / 3))" # "a"를 세트하고 "t2"를 계산.
          
\
이스케이프(escape). [역슬래쉬] \X라 고 하면 X 문자를 "이스케이프" 시키고, 'X' 라고 "쿼우팅" 시키는 것과 동일한 효과를 갖습니다. \는 "나 '이 문자 그대로 해석되도록 쿼우트 할 때 쓰일 수도 있습니다.
이스케이프된 문자들에 대한 설명이 6장에 자세하게 되어 있습니다.
/
파일명 경로 구분자. [슬래쉬] 파일명에 등장하는 각 요소들을 구분해 줍니다(/home/bozo/projects/Makefile 처럼).
나누기 산술 연산자도 됩니다.
`
명령어 치환(command substitution). [백틱(backticks)] `명령어` 라고 하면 명령어의 결과를 변수값으로 설정할 수가 있습니다. 다른 말로 backticks나 역쿼우트(backquote)라고도 합니다.
:
널 명령어(null command). 쉘의 "NOP"(no op, 아무 동작도 않함)에 해당합니다. 쉘 내장 명령인 true의 동의어라고도 볼 수 있습니다. 주의할 점은 :은 bash 내장 명령이기 때문에 종료 상태는 0이라는 것입니다.
          : echo $? # 0
          
무한 루프:
          while : do 첫번째 연산 두번째 연산 ... n번째 연산 done # 이는 다음과 같습니다: # while true # do # ... # done
          
if/then 테스트 문의 Placeholder:
          if condition then : # 아무것도 안 하고 계속 진행 else 어떤 작업 fi
          
이진 연산의 placeholder 제공, 예 8-1 와 디폴트 매개변수 참고.
          : ${username=`whoami`} # "username"이 명령어나 내장 명령어가 아닌 경우에 # ${username=`whoami`} 에 : 없이 쓰면 에러가 납니다.
          
here document가 나올 곳의 placeholder를 제공. 예 17-8 참고.
매개변수 치환을 써서 변수의 문자열 평가(예 9-10 참고).
          : ${HOSTNAME?} ${USER?} ${MAIL?} # 필수적인 환경변수중 하나라도 세트가 안 돼 있다면 에러를 출력.
          
재지향 연산자인 >과 같이 써서 특정 파일의 퍼미션 변경 없이 크기를 0으로 만들어 줍니다. 파일이 없었다면 새로 만들어 냅니다.
          : > data.xxx # "data.xxx"은 이제 빈 파일입니다. # cat /dev/null >data.xxx 라고 한 것과 동일하지만 # ":"가 내장 명령어이기 때문에 새 프로세스를 포크(fork) 시키지 않습니다.
          
예 12-11 참고.
역시 재지향 연산자인 >>과 같이 쓰면 파일의 억세스/변경 시간을 업데이트 해 줍니다(: >> new_file). 파일이 없었다면 새로 만들어 냅니다. touch와 같습니다.
참고: 보통 파일에만 사용하고 파이프나 심볼릭 링크, 특수 파일에는 사용하지 마세요.
권장하는 방법은 아닙니다만, 주석의 시작을 나타낼 때 쓸 수도 있습니다. 주석에 #을 쓰게 되면 그 줄의 나머지 부분에 대해서 에러 확인을 안 하기 때문에 어떤 문장도 올 수 있지만 :의 경우는 다릅니다.
          : 이 주석은 에러를 발생시킵니다, ( if [ $x -eq 3] ).
          
":"는 또한 /etc/passwd와 $PATH 변수에서 필드 구분자로도 쓰입니다.
          bash$ echo $PATH /usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/sbin:/usr/sbin:/usr/games
          
!
테스트나 종료 상태의 의미를 반대나 부정해 줍니다. ! 연산자는 해당 명령어의 종료 상태를 반대로 해 놓습니다(예 3-2 참고). 또한, 테스트 연산자의 의미도 거꾸로 바꿔 주는데 예를 들어, "equal"= )을 "not-equal" ( != )로 해석하게 해 줍니다. ! 연산자는 bash 키워드입니다.
다른 상황에서는 간접 변수 참조의 의미로도 쓰입니다.
*
와일드 카드. [별표] * 문자는 정규 표현식에서 0개 이상의 문자를 나타내는 것과 동일하게 파일명 확장(globbing)에서 "와일드 카드"처 럼 쓰입니다.
이중 별표, **, 는 수학의 누승(累乘, exponentiation) 연산자입니다.
?
와일드 카드(하나의 문자). [물음표] ? 문자는 확장 정규 표현식에서 한 문자를 나타내는 것과 마찬가지로 글로빙(globbing)에서 파일명 확장을 나타내는 한 문자짜리 "와일드 카드"의 역할을 합니다.
?은 이중 소괄호에서 C 스타일의 삼중 연산자로도 쓰입니다. 예 9-22를 참고하세요.
$
          var1=5 var2=23skidoo echo $var1 # 5 echo $var2 # 23skidoo
          
${}
$*$@
()
명령어 그룹.
          (a=hello; echo $a)
          
중요: 소괄호로 묶인 명령어들은 서브쉘에서 동작합니다.
스크립트의 다른 곳에서는 소괄호 안의 서브쉘에 들어 있는 변수들을 볼 수가 없습니다. 부모 프로세스인 스크립트는 자식 프로세스(서브쉘)에서 만들어진 변수를 읽을 수가 없습니다.
          a=123 ( a=321; ) echo "a = $a" # a = 123 # 소괄호 안의 "a" 는 지역변수처럼 동작합니다.
          
배열 초기화.
          Array=(element1 element2 element3)
          
{xxx,yyy,zzz,...}
중괄호 확장.
          grep Linux file*.{txt,htm*} # "fileA.txt", "file2.txt", "fileR.html", "file-87.htm" 등등의 파일에서 # "Linux"가 들어 있는 것을 모두 찾음
          
명령어는 중괄호안의 콤마로 분리 지정된 파일 스펙에 맞게 동작할 것입니다. [1] 파일명 확장(globbing)은 중괄호 안에서 지정된 파일 스펙에 적용됩니다.
경고
빈 칸은 쿼우트(quote)나 이스케이프(escape)되지 않고 중괄호에서 쓰일 수 없습니다.
echo {file1,file2}\ :{\ A," B",' C'}
file1 : A file1 : B file1 : C file2 : A file2 : B file2 : C
{}
코드 블럭. [중괄호] "인라인 그룹"이라고도 부르는 중괄호 한 쌍은 실제로 익명의 함수를 만들어 냅니다만 보통의 함수와는 달리 코드 블럭 안의 변수들을 스크립트의 다른 곳에서 볼 수가 있습니다.
          bash$ { local a; a=123; } bash: local: can only be used in a function
          
          a=123 { a=321; } echo "a = $a" # a = 321 (코드 블럭에서 설정된 값) # Thanks, S.C.
          
중괄호로 묶인 코드 블럭은 I/O 재지향되거나 재지향을 받을 수 있습니다.
예 4-1. 코드 블럭과 I/O 재지향
          #!/bin/bash # /etc/fstab 읽기 File=/etc/fstab { read line1 read line2 } < $File echo "$File 파일의 첫번째 줄:" echo "$line1" echo echo "$File 파일의 두번째 줄:" echo "$line2" exit 0
          
예 4-2. 코드 블럭의 결과를 파일로 저장하기
          #!/bin/bash # rpm-check.sh # rpm 파일에 대해서 설치가능여부, 설치정보, 설치목록에 대해서 쿼리를 하고, #+ 그 결과를 파일로 저장합니다. # # 이 스크립트는 코드 블럭이 어떻게 쓰이는지 보여줍니다. SUCCESS=0 E_NOARGS=65 if [ -z "$1" ] then echo "사용법: `basename $0` rpm-file" exit $E_NOARGS fi { echo echo "아카이브 정보:" rpm -qpi $1 # 설치정보 쿼리. echo echo "아카이브 목록:" rpm -qpl $1 # 설치목록 쿼리. echo rpm -i --test $1 # 설치가능여부 쿼리. if [ "$?" -eq $SUCCESS ] then echo "$1 는 설치될 수 있습니다." else echo "$1 는 설치될 수 없습니다." fi echo } > "$1.test" # 블럭의 모든 출력을 파일로 재지향. echo "$1.test 파일에 rpm 테스트의 결과가 저장되었습니다." # 여기서 쓰인 옵션에 대한 설명은 맨 페이지를 참고하세요. exit 0
          
참고: 위에서 설명했던 (소괄호)로 묶인 명령어 그룹과는 달리 {중괄호}로 묶인 코드 블럭은 보통은 서브쉘을 띄우지 않습니다.[2]
{} \;
경로명. 주로 find에서 쓰이고, 쉘 내장 명령이 아닙니다.
참고: ";" 는 find 명령어의 -exec 옵션이 여러개 나올 때 끝을 나타내기 때문에 쉘이 해석하는 것을 막기 위해서 이스케이프 시켜줘야 됩니다.
[ ]
테스트.
[ ] 사이의 테스트문. [는 쉘 내장 명령인 test와 동의어로서, 외부 명령어인 /usr/bin/test의 링크가 아닙니다.
[[ ]]
테스트.
[[ ]] 사이의 테스트문(쉘 키워드).
더 자세한 사항은 [[ ... ]]을 참고하세요.
(( ))
정수 확장.
(( ))에 들어 있는 정수 표현식을 확장하고 평가해 줍니다.
더 자세한 설명은 (( ... ))를 참고하세요.
> >& >> <
scriptname >filename 은 scriptname의 결과를 filename으 로 재지향시킵니다. 이 때, fielname이 이미 있다면 덮어 써집니다.
command >&2는 command의 결과를 표준에러로 재지향 시킵니다.
scriptname >>filename은 scriptname의 결과를 filename 으로 덧붙입니다. 이 때, filename이 없다면 새로 만듭니다.
프로세스 치환(process substitution).
(command)>
<(command)
"<" 와 ">" 문자는 다른 문맥에서 문자열 비교 연산자로 동작합니다.
또 다른 문맥에서는 정수 비교 연산자로 동작합니다. 예 12-6를 참고하세요.
<<
here document에서 쓰이는 재지향.
|
파이프. 여러 명령어들을 연결하는 방법으로써, 한 명령어의 출력을 다음 명령어나 쉘에게 전달.
          echo ls -l | sh # "echo ls -l" 의 출력을 쉘에게 전달하는데, #+ 그냥 "ls -l" 라고 한 것과 똑같습니다. cat *.lst | sort | uniq # 모든 ".lst" 파일들을 합친 다음 정렬하고 중복된 줄들을 지웁니다.
          
명령어의 출력이나 명령어 자체를 스크립트로 파이프를 걸 수도 있습니다.
          #!/bin/bash # uppercase.sh : 입력을 대문자로 바꿔줌. tr 'a-z' 'A-Z' # 한 글자짜리 파일 이름이 생기는 걸 막기 위해서 #+ 문자 범위는 꼭 쿼우트 시켜야 합니다. exit 0
          
자, 이제 ls -l의 출력에 파이프를 걸어 이 스크립트로 넘겨 봅시다.
          bash$ ls -l | ./uppercase.sh -RW-RW-R-- 1 BOZO BOZO 109 APR 7 19:49 1.TXT -RW-RW-R-- 1 BOZO BOZO 109 APR 14 16:48 2.TXT -RW-R--R-- 1 BOZO BOZO 725 APR 20 20:56 DATA-FILE
          
참고: 파이프로 묶인 각 프로세스의 표준출력은 다음 명령어의 표준입력으로 읽혀야 합니다. 이런식으로 동작하지 않는다면 데이타의 흐름은 블럭될 것이고 파이프는 생각했던대로 동작하지 않을 것입니다.
          cat file1 file2 | ls -l | sort # "cat file1 file2" 의 출력은 나타나지 않습니다.
          
파이프는 자식 프로세스로 돌기 때문에 스크립트의 변수값을 바꿀 수가 없습니다.
          variable="initial_value" echo "new_value" | read variable echo "variable = $variable" # variable = initial_value
          
파이프로 연결된 명령어중 하나가 취소된다면 전체 실행이 취소되는데 이를 broken pipe라고 하고, 이 때 SIGPIPE 시그널이 발생 됩니다.
>|
강제 재지향(noclobber 옵션이 켜 있더라도). 파일이 이미 존재하더라도 강제로 덮어 쓰게 합니다.
&
작업을 백그라운드로 돌리기. 명령어 뒤에 &를 붙여 주면 백그라운드로 실행됩니다.
          bash$ sleep 10 & [1] 850 [1]+ Done sleep 10
          
경고
스크립트에서 어떤 명령어를 백그라운드로 돌리게 되면 키가 눌리길 기다리면서 스크립트가 멈춰버립니다. 다행스럽게도 이런 상황을 피해 갈 수 있는 방법이 있습니다.
-
표준입력(stdin)과 표준출력(stdout) 서로간의 재지향. [대쉬]
          (cd /source/directory && tar cf - . ) | (cd /dest/directory && tar xpvf -) # 한 디렉토리의 전체 파일 구조를 다른 디렉토리로 옮김 # [Alan Cox <a.cox@swansea.ac.uk> 제공, 약간의 수정] # 1) cd /source/directory 옮겨질 파일들이 있는 소스 디렉토리 # 2) && "And-list": 'cd' 명령이 성공하면 다음 명령어가 실행됨 # 3) tar cf - . 'c' 옵션은 새 아카이브를 만들라는 명령어 # 'f'(file) 옵션은 그 뒤에 나오는 '-'에 의해 타켓 파일을 표준 출력으로 지정해 주고, # 현재 디렉토리 트리(.)를 대상으로 하게 합니다. # 4) | 파이프를 걸고 # 5) ( ... ) 서브쉘 # 6) cd /dest/directory 옮길 디렉토리로 이동 # 7) && 위에서 설명했던 "And-list" # 8) tar xpvf - 아카이브를 풀고('x'), 소유권과 파일 퍼미션을 유지(' p')하고 # 표준출력으로 메세지를 많이(verbose) 찍게 하고('v') # 표준입력에서 데이터를 읽어 들임('f' 다음의 '-') # # 'x'는 명령어고, 'p', 'v', 'f'는 옵션입니다. 주의하세요. # 헥헥~~~~ # 똑같지만 더 우아한 방법: # cd source-directory # tar cf - . | (cd ../target-directory; tar xzf -) # # cp -a /source/directory /dest 도 같은 결과가 나옵니다.
          
          bunzip2 linux-2.4.3.tar.bz2 | tar xvf - # --tar 파일을 풀어서 -- | --"tar" 에게 넘김 -- # "tar"에 "bunzip2"를 처리하는 패치가 안 돼 있다면 # 파이프를 써서 두 단계로 나누어 처리를 해 줘야 합니다. # 여기서는 "bzip"으로 압축된 커널 소스를 푸는 것을 보여줍니다.
          
여기서 쓰인 "-"는 Bash 연산자가 아니고, tar나 cat 같은 몇몇 유닉스 유틸리티들이 인식해서 표준출력으로 쓰도록 해주는 옵션임에 주의하세요.
파일명이 나와야 할 곳에 -이 나오면 표준출력으로 결과를 재지향하든지(tar cf에 서 가끔 쓰죠), 실제 파일에서 입력을 받지 않고 표준입력에서 받도록 재지향 하게 해 줍니다. 주로 파일을 다루는 유틸리티들을 파이프에서 필터로 쓸 때 이 방법을 씁니다.
          bash$ file 사용법: file [-bciknvzL] [-f namefile] [-m magicfiles] file...
          
file이 명령어줄에서 옵션없이 불리면 에러 메세지를 내면서 실패합니다.
          bash$ file - #!/bin/bash standard input: Bourne-Again shell script text executable
          
이 번에는 자신의 입력을 표준입력에서 받고 그 결과를 필터링 합니다.
- 는 표준출력을 다른 명령어로 파이프 시키는데 쓰일 수 있습니다. 이렇게 하면 파일의 앞쪽에 줄을 삽입하기같은 묘기도 부릴 수 있습니다.
diff를 써서 섹션을 가진 두 파일을 비교해 보기 바랍니다.
grep bash file1 | diff file2 -
마지막으로, tar에 -를 쓴 현실적인 예제입니다.
예 4-3. 최근 하루동안 변경된 파일들을 백업하기
          #!/bin/bash # 현재 디렉토리의 모든 파일중 최근 24시간 안에 변경된 파일들을 #+ 타르로 묶고 gzip으로 압축한 "타르볼"로 백업 NOARGS=0 E_BADARGS=65 if [ $# = $NOARGS ] then echo "사용법: `basename $0` filename" exit $E_BADARGS fi tar cvf - `find . -mtime -1 -type f -print` > $1.tar gzip $1.tar # 너무 많은 파일이 발견되거나 파일명에 빈 칸이 들어있다면 위의 코드는 #+ 실패할 수도 있다고 Stephane Chazelas 가 지적해 주었습니다. # 그가 제안한 다른 방법은 다음과 같습니다: # ------------------------------------------------------------- # find . -mtime -1 -type f -print0 | xargs -0 tar rvf "$1.tar" # "find"의 GNU 버전을 쓴 방법. # find . -mtime -1 -type f -exec tar rvf "$1.tar" '{}' \; # 다른 유닉스에서도 쓸 수 있지만 더 느린 방법. exit 0
          
경고
파일명이 -로 시작하는 파일이 - 재지향 연산자와 같이 쓰이면 문제가 생길 수도 있습니다. 스크립트 내에서 이런 사항을 확인한 다음에 ./-FILENAME이나 $PWD/-FILENAME등으로 바꿔서 처리해 줘야 합니다.
또한, 변수의 값이 -로 시작할 경우에도 비슷한 문제가 생길 수 있습니다.
          var="-n" echo $var # "echo -n" 처럼 해석이 되어 결과가 안 나타납니다.
          
-
바로 전 작업 디렉토리. [대쉬] cd - 라고 하면 $OLDPWD 환경 변수를 이용해서 바로 전 작업 디렉토리로 옮겨갑니다.
경고
방금 위에서 설명한 재지향 연산자인 "-"와 헷갈리면 안 됩니다. "-"는 문맥에 따라 알맞게 해석됩니다.
-
빼기. 산술 연산에서 쓰이는 빼기 부호.
=
          a=28 echo $a # 28
          
"="가 다른 문맥에서 쓰이면 문자열 비교 연산자입니다.
+
더하기. 덧셈 산술 연산자.
+가 다른 문맥에서 쓰이면 정규 표현식 연산자입니다.
%
나머지(modulo). 나눗셈의 나머지 산술 연산자.
%가 다른 문맥에서 쓰이면 패턴 매칭 연산자입니다.
~
홈 디렉토리. [틸드] 이 문자는 $HOME 내부 변수에 해당합니다. ~bozo 는 bozo의 홈 디렉토리를 나타내고ls ~bozo 는 그 홈 디렉토리의 내용을 보여줍니다. ~/ 은 현재 사용자의 홈 디렉토리를 나타내고, ls ~/ 는 그 홈 디렉토리의 내용을 보여줍니다.
          bash$ echo ~bozo /home/bozo bash$ echo ~ /home/bozo bash$ echo ~/ /home/bozo/ bash$ echo ~: /home/bozo: bash$ echo ~nonexistent-user ~nonexistent-user
          
~+
현재 작업 디렉토리. 이 문자는 $PWD 내부 변수에 해당합니다.
~-
바로 전 작업 디렉토리. 이 문자는 $OLDPWD 내부 변수에 해당합니다.
제어 문자
터미널이나 텍스트 디스플레이의 동작을 변경. 제어 문자는 CONTROL + key 조합으로 나타낼 수 있습니다.
  • Ctl-C
    포그라운드 작업을 끝냄.
  • Ctl-D
    쉘에서 로그 아웃(exit와 비슷함).
    "EOF" (파일끝, end of file). 표준입력에서 들어오는 입력을 끝냄.
  • Ctl-G
    "벨(BEL)"(삑 소리).
  • Ctl-H
    백스페이스(backspace).
  • Ctl-J
    캐리지 리턴(carriage return).
  • Ctl-L
    폼피드(formfeed, 터미널 화면을 청소). clear 명령어와 똑같은 효과.
  • Ctl-M
    뉴라인(Newline).
  • Ctl-U
    입력줄을 지움.
  • Ctl-Z
    포그라운드 작업을 잠시 멈춤.
공백문자(whitespace)
명령어나 변수의 구분자 역할. 공백문자는 빈칸, 탭, 빈줄들의 어떠한 조합들로 이루어져 있습니다. 변수 할당같은 상황에서 공백문자를 쓰면 문법 에러가 납니다.
빈줄은 스크립트 동작에 아무 영향도 주지 않기 때문에 기능별로 구분시켜서 보기 좋게 하는데 쓸 수 있습니다.
특수 변수인 $IFS는 어떤 명령어의 입력 필드를 구분해 주는데 이 변수의 디폴트값은 공백문자입니다.

주석

[1]
쉘은 중괄호 확장을 시도할 것이고, 명령어는 확장된 결과에 따라 동작합니다.
[2]
예외: 중괄호로 묶인 코드 블럭이 파이프의 일부분으로 돈다면 서브쉘로 돌 수도 있습니다.
          ls | { read firstline; read secondline; } # 에러. 중괄호 안의 코드 블럭은 서브쉘로 돌기 때문에 "ls"의 결과가 # 블럭 안의 변수로 전달될 수 없습니다. echo "첫번째 줄은 $firstline; 두번째 줄은 $secondline" # 동작하지 않을 겁니다. # Thanks, S.C.