[scala] 쉘 실행하기

scala 2016. 12. 13. 20:24



 scala에서 프로세스를 실행하려면 scala.sys.process._을 import하고, 문자열에 .! (또는 !)을 실행한다. (마치 regular expression처럼..) 


import scala.sys.process._
val result = "ls -al /Users/samuel.kim/dev".!
println(result)

결과는 다음과 같다. 


total 48

drwxr-xr-x   8 samuel.kim  staff   272 12 11 01:02 .

drwxr-xr-x+ 64 samuel.kim  staff  2176 12 12 18:20 ..

-rw-r--r--   1 samuel.kim  staff     8 12 12 21:48 a

-rw-r--r--   1 samuel.kim  staff     8 12 11 01:02 b

..

0


주의할 점은 !는 ProcessBuilder 클래스의 메소드로서 리턴 값은 Int이다. 즉, 결과를 출력하고 리턴 값으로 0만 받는 형태이다. 


def ! : Int


전체 결과를 String으로 얻으려면, !!을 사용한다. 


import scala.sys.process._
val result = "ls -al /Users/samuel.kim/dev".!!
println(result)


결과는 다음과 같다.


total 48

drwxr-xr-x   8 samuel.kim  staff   272 12 11 01:02 .

drwxr-xr-x+ 64 samuel.kim  staff  2176 12 12 18:20 ..

-rw-r--r--   1 samuel.kim  staff     8 12 12 21:48 a

-rw-r--r--   1 samuel.kim  staff     8 12 11 01:02 b

..



!!의 리턴 값은 String이다. 

def !! : String





그리고, List로 저장할 수 있다. 

import scala.sys.process._
val result = List("ls -al /Users/samuel.kim/dev".!!)
result.foreach(println)
println(result.size)

결과는 다음과 같다. 


total 48

drwxr-xr-x   8 samuel.kim  staff   272 12 11 01:02 .

drwxr-xr-x+ 64 samuel.kim  staff  2176 12 12 18:20 ..

-rw-r--r--   1 samuel.kim  staff     8 12 12 21:48 a

-rw-r--r--   1 samuel.kim  staff     8 12 11 01:02 b

..

1






파이프라인을 사용하면, 에러가 발생한다.

import scala.sys.process._
val result = List("ls -al /Users/samuel.kim/dev | wc -l".!!)
result.foreach(println)


ls: a: No such file or directory

ls: grep: No such file or directory

ls: |: No such file or directory




다음처럼 커맨드 단위로 잘개 쪼개고 #을 파이프에 붙여야 한다. 


import scala.sys.process._
val result = List(("ls -al /Users/samuel.kim/dev" #| "wc -l ").!!)
result.foreach(println)

결과는 다음과 같다. 





이번에는 >>이라는 표준 출력(stdout) append를 사용한다. #|처럼 #>>을 사용하며, #>> 다음에는 new File()을 생성한다. 


import java.io.File
import scala.sys.process._
val result = ("ls -al /Users/samuel.kim/dev" #| "wc -l " #>> new File(s"/Users/samuel.kim/dev/a.txt")).!
println(result)
val result2 = ("cat /Users/samuel.kim/dev/a.txt".!!)
println(result2)


결과는 다음과 같다.


0

       8



스칼라에서는 표준 입력/출력을 처리할 수 있다.


#<   Redirect STDIN


#>   Redirect STDOUT

#>>  Append to STDOUT


#&&  Create an AND list

#!!  Create an OR list



자세한 내용은 scala.sys.process.ProcessBuilder api를 참조한다.





이를 바탕으로 함수를 만들 수 있다. 


def get(filter: String) = {
val command = s"ls -al /Users/samuel.kim/dev" #| s"grep $filter "
println(command)
command
}

val result = get("xx").!!
println(result)

결과는 다음과 같다.


 ( [ls, -al, /Users/samuel.kim/dev] #| [grep, xx] ) 

drwxr-xr-x   9 samuel.kim  staff   306 Dec  5 21:16 xx





scala는 쉘의 리턴값이 정상이 아니면 Exception이 발생한다. Try를 써주면 Exception 대신 Failure로 처리해 준다.


def get(filter: String) = {
val command = s"ls -al /Users/samuel.kim/dev" #| s"grep $filter "
println(command)
command
}

val result = Try(get("bbb").!!)
println(result)

결과는 다음과 같다.


 ( [ls, -al, /Users/samuel.kim/dev] #| [grep, bbb] ) 

Failure(java.lang.RuntimeException: Nonzero exit value: 1)

Posted by '김용환'
,


scala에서 클래스를 생성하는 방법이다.


class Person {
}
new Person()


class Person(id: Int)
new Person(1)


클래스는 this라는 보조 생성자로 객체를 생성할 수 있다. 


그리고, Option 타입을 사용하면 풍부한 생성이 가능하다. 


하지만, case class를 사용하여 new 객체를 하지 않도록 할 때 일부 코드에서는 컴파일 에러가 발생한다. 

case class Person(id: Int, name: String, department: Option[String]) {
def this(id: Int) = this(id, "no-name")

def this(id: Int, name: String) = this(id, name, Some("no-name"))
}

new Person(1, "matt")
new Person(2)
new Person(3, "samuel", Some("develop"))

//Person(1) // compile error
//Person(2, "jack") // compile error
Person(3, "samuel", Some("develop"))


보조 생성자의 한계가 보이기 때문에, 이때 동반자 객체(companion object)를 활용한다.


이전에 컴파일 에러가 발생했던 부분이 사라지고 더욱 Rich하게 사용할 수 있다. 




case class Person(id: Int, name: String, department: Option[String]) {
def this(id: Int) = this(id, "no-name")

def this(id: Int, name: String) = this(id, name, Some("no-name"))
}

object Person {
def apply(id: Int) = new Person(id)

def apply(id: Int, name: String) = new Person(id)
}

new Person(1, "matt")
new Person(2)
new Person(3, "samuel", Some("develop"))


Person(1)
Person(2, "jack") Person(3, "samuel", Some("develop"))





Posted by '김용환'
,


java7 이전에서 Map의 내용을 확인하기 위해 출력하는 코드는 verbose 하다.


Map<Integer,String> map = new HashMap<Integer,String>();


for(Map.Entry<Integer,String> entry: map.entrySet()){

    System.out.println(entry.getKey()+" - "+ entry.getValue());

}




Apache Collections 라이브러리는  MapUtils.debugPrint 메소드를 통해 Map을 출력할 수 있다. 이 방법은 slf4j나 log4j의 OutputStream을 얻기 어려워 쓰기 애매한 부분이 있다. 


MapUtils.debugPrint(System.out, "myMap", map);




java8부터는 stream의 forEach를 사용하면 그나마 좀 쓰기 편한 듯 하다. 



map.forEach((key, value) -> { logger.debug(key + " : " + value); });

'java core' 카테고리의 다른 글

jnr  (0) 2017.02.27
enum 데이터를 리스트(list)로 얻기  (0) 2016.12.19
자바의 clone, guava의 Maps, Lists 사용  (0) 2016.12.01
JVM의 safepoint  (0) 2016.09.08
JDK의 Flight Recorder 라이선스  (0) 2016.09.08
Posted by '김용환'
,



scala의 어떤 클래스가 클래스를 상속받고 트레이트(trait)를 믹스인하는 초기화는 다음 순서와 같다.


object Main extends App {
trait T1 {
println("t1") // 4
}

trait T2 {
println("t2") // 5
}

class BaseParent {
println("base-parent") // 2
}

class Parent extends BaseParent {
println("parent") // 3
}

class Example extends Parent with T1 with T2 {
println("example") // 6
}

println(s"before") // 1
new Example
println(s"after") // 7
}


결과는 다음과 같다. 


부모 클래스의 부모 클래스부터 초기화되고 다음에 부모 클래스가 생성된다. 

다음에 믹스인(mix in)한 트레이트가 초기화된다. 


before

base-parent

parent

t1

t2

example

after





'scala' 카테고리의 다른 글

[scala] 쉘 실행하기  (0) 2016.12.13
[scala] 클래스 초기화하기(생성)  (0) 2016.12.13
[scala] for 내장  (0) 2016.12.08
[scala] try-catch/Try-match/Either/Validation  (0) 2016.12.06
[scala] 부분 적용 함수 / 커링 / 부분 함수  (0) 2016.12.05
Posted by '김용환'
,