#TIL #elixir atom 키를 사용해 struct를 만들거나 업데이트하고 싶다면

defmodule User do
  defstruct name: "ohyecloudy"
end

iex> unknown = struct(User, name: "unknown")
%User{name: "unknown"}

물론 생성할 때도 사용할 수 있다. keyword로 바꾸고 싶은 키와 값을 넘기면 된다.

iex> put_in(unknown.name, "ohyecloudy")
%User{name: "ohyecloudy”}

Dot-based syntax로 접근하면 얼마든지 업데이트할 수 있다.

iex> put_in(unknown, [:name], "ohyecloudy")
** (UndefinedFunctionError) function User.get_and_update/3 is undefined (User does not implement the Access behaviour)
    User.get_and_update(%User{name: "unknown"}, :name, #Function<16.9473146/1 in Kernel.put_in/3>)
    (elixir) lib/access.ex:370: Access.get_and_update/3
    (elixir) lib/kernel.ex:2114: Kernel.put_in/3

map과 다르게 struct는 Bracket-based access는 불가능하다.

iex> struct(unknown, name: "ohyecloudy")
%User{name: "ohyecloudy”}

struct/2, struct!/2 함수를 사용하면 keyword로 업데이트할 수 있다.

#TIL #PostgreSQL pager off

대화형 터미널(interactive terminal)에서 쿼리 결과가 길면 pager가 편하다. 한 페이지에 결과가 다 안 보이기 때문이다. 앞뒤로 왔다 갔다 하면서 확인할 수 있어서 편하다. 하지만 결과가 짧거나 결과를 참고하며 이후 쿼리를 짜고 싶을 때는 pager가 방해된다.

=> \pset pager off

대화형 터미널에서 입력하면 pager를 끌 수 있다

참고 - Turn off pager for psql’s interactive output - serverfault.com

#TIL #elixir get_in 함수에 default 값을 넣는 곳은 없나?

리턴 값이 nil인지 검사해서 다른 값을 사용하는 것보단 nil일 때, 사용할 default 값을 인자로 넘길 수 있다면 로직이 깔끔해진다. 인자를 3개 받는 get_in/3을 기대했지만, get_in/2 밖에 없다. 필요하면 만들어 써야 한다.

def get_in(data, path, default) do
  case get_in(data, path) do
    nil   -> default
    other -> other
  end
end

이렇게 한번 감싸거나

get_in(data, path) || default

short-circuit evaluation에 살짝 기대거나. 이 바닥에선 많이 쓰니깐 이렇게 써도 무방하다.

참고 - get_in/3 with default value - elixir-lang-core

#TIL #linux 읽기 쉬운 파일 크기로 ls

/ddiary/assets/2018-11-09-til-linux-ls-with-unit-suffixes-00.jpg

$ ls -lh

천 단위로 끊어서 대충 읽으려고 안 해도 된다. -h 옵션을 사용하면 Byte, Kilobyte, Megabyte 과 같은 유닛 접미사를 출력한다.

참고

#TIL #docker 컨테이너 timezone 세팅하는 법

$ docker run -e "TZ=Asia/Seoul”

-e 옵션을 사용한다. 컨테이너 TZ 환경 변수에 원하는 시간대를 할당하면 된다.

참고

#TIL #vim URL을 여는 키바인딩 gx

gx 키를 누르면 url을 디폴트 웹브라우저로 연다.

gx 키를 알기 전에는 gf 키로 url을 열었다. emacs evil mode에서 gf를 누르면 find file을 실행한다. url을 인식해 웹브라우저를 호출한다. 열긴 열지만 한 단계를 더 거쳐야 했다. gx 키를 누르면 그런 거 없고 한 번에 팍 뜬다.

#TIL #git 구식 branch를 최신으로 갱신하고 싶다면

$ git checkout master
$ git merge -s ours obsolete-branch

다른 브랜치 변경 사항을 무시한다. merge 커밋이 생길 수 있다는 것만 빼면 obsolete-branch를 지우고 다시 따는 것과 같다.

-s <strategy>

--strategy=<strategy>

Use the given merge strategy; can be supplied more than once to specify them in the order they should be tried. If there is no -s option, a built-in list of strategies is used instead (git merge-recursive when merging a single head, git merge-octopus otherwise).

https://git-scm.com/docs/git-merge

ours, theirs 용어는 항상 헷갈린다. ours는 현재 체크아웃한 브랜치고 theirs는 merge 대상 브랜치다.

#TIL #elixir 리스트에서 마지막 원소만 제외 혹은 마지막 원소만 가져오기

iex> Enum.drop([1, 2, 3], -1)
[1, 2]

iex> Enum.take([1, 2, 3], -1)
[3]

C++이 고향이라서 음수 인덱스는 아직도 어색하다.

참고

#TIL #docker 종료하지 않고 계속 exec로 명령을 할 수 있게 하려면

docker를 tpass 프로그램을 테스트하는 데 사용했다. 간단한 테스트다. 다음과 같은 순서로 진행한다. docker exec 명령을 내린다. 결과값을 검사한다. 다만 이렇게 하려면 컨테이너가 입력을 받을 수 있는 상태여야 한다. 즉, 실행 상태여야 한다. 종료하면 안 된다.

$ docker run -di --rm --name user_a test-add-user bash

bash를 실행해놓고 detach를 하면 되지 않을까? 아니다. 그냥 실행만 하면 안 되고 --interactive , -i 옵션을 써서 STDIN 유지를 해야 한다. 그럼 종료되지 않는다. 입력을 기다리는 상태가 되기 때문이다.

참고 - Why docker container exits immediately - stackoverflow.com

#TIL #bash cut과 dirname으로 path 조작

$ echo a/b/c/d | cut -d/ -f 2
b

$ echo a/b/c/d | cut -d/ -f -2
a/b

$ echo a/b/c/d | cut -d/ -f 2-
b/c/d

-d 옵션으로 자를 구분 문자(delimiter)를 정의한다. index는 1부터 시작한다. -f 옵션으로 남길 index를 입력한다.

$ dirname a/b/c/d
a/b/c

마지막 디렉터리만 없애고 싶을 때는 dirname 명령어를 사용한다.

참고

#TIL #bash 확장자 일괄 변경

$ for file in *.jpeg; do mv "$file" "$(basename "$file" .jpeg).jpg"; done

*.jpeg 파일 이름 확장(expansion)은 패턴에 일치하는 파일 이름 리스트로 대체된다. basename 프로그램으로 .jpeg 확장자를 제거한다. 거기에 .jpg 확장자를 붙여서 mv 프로그램 호출.

참고 - How do I rename the extension for a batch of files? - stackoverflow.com

#TIL #unity 씬 로드 전에 함수 호출

씬 로드 전에 함수를 호출할 방법이 있을까?

class MyClass
{
    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
    static void OnBeforeSceneLoadRuntimeMethod()
    {
        Debug.Log("Before first scene loaded");
    }

RuntimeInitializeOnLoadMethod 어트리뷰트를 사용하면 된다. 먼저 찾은 <Best way to initialize static class not attached to a GameObject> 글에선 에디터와 독립(standalone) 실행을 분리해서 구현했던데, 하나로만 해도 잘 된다.

#TIL #batch #unity 프로젝트를 바로 여는 배치 스크립트

C:\> type open_project.cmd
start "" "C:\Program Files\Unity\Editor\Unity.exe" -projectPath "C:\my_project"

매일 여는 unity 프로젝트. 배치파일 하나 만들어 두었다.

참고

#TIL #bash 디폴트 파라미터 값

${parameter:-word}

parameter가 null 이거나 unset이면 word로 대체된다.

user=$1
pass_directory=${2:-password_store}

활용하면 optional parameter로 사용할 수 있다. 2번째 인자가 있으면 그걸 pass_directory 변수에 할당하고 없다면 password_store를 할당한다.

#TIL vagrant로 docker 세팅

<#TIL vagrant로 centos, docker 세팅> 글처럼만 해도 편했는데, 더 편하게 할 수 있다.

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/trusty64"
  config.vm.provision "docker"
end

provision을 docker로 설정하면 다 알아서 해준다.

#TIL #linux 랜덤 엔트로피가 모자랄 때

Not enough random bytes available. Please do some other work to give the OS a chance to collect more entropy! (Need xxx more bytes)

gpg key 생성 실패 메시지. 별일 다 있네. 엔트로피가 모잘린다니 linux virtual machine에서 docker 컨테이너를 실행하면 몰라도 엔간해선 이런 메시지를 보기 힘들다.

$ cat /proc/sys/kernel/random/entropy_avail
137

이런 엔트로피론 택도 없다.

$ sudo apt-get install haveged
$ haveged
$ cat /proc/sys/kernel/random/entropy_avail
2430

이럴 땐, haveged 프로그램을 사용하면 된다.

참고 - How to use GnuPG inside Docker containers, as it is missing entropy? - stackoverflow.com

#TIL #git remote 브랜치 제거

$ git push origin :feature-1

refspec에 src 부분을 없애서 리모트 브랜치를 삭제한다. 난 이 명령만 있는 줄 알았는데.

$ git push origin --delete feature-1

delete 옵션을 사용하면 된다. 1.7 버전부터 추가됐다니 생각보다 오래됐다.

참고 - How do I delete a Git branch both locally and remotely? - stackoverflow.com

#TIL #macOS 그림자 없이 윈도우 스크린샷 찍는 방법

Command(⌘)-Shift-4, 스페이스 바, 클릭

메뉴 막대 혹은 윈도우를 깔끔하게 찍는 방법을 알아내긴 했는데, 그림자까지 예쁘게 그려주는 바람에 찍은 윈도우가 작게 나와 잘 안 보일 때가 있다.

Command(⌘)-Shift-4, 스페이스 바, Option 키 누른채 클릭

option 키를 누르고 클릭하면 윈도우만 찍힌다.

참고 - OS X에서 화면을 캡쳐하는 방법 총정리 - 그리고 잘 알려져 있지 않는 숨은 기능 소개 - macnews.tistory.com

#TIL #git origin 리모트 저장소 변경

$ cd existing_repo
$ git remote rename origin old-origin
$ git remote add origin new_repo_url
$ git push -u origin --all
$ git push -u origin --tags
$ git remote remove old-origin

저장소를 만드니 gitlab이 안내해줬다.

$ git remote remove origin

이름 변경 없이 지운 후에 진행해도 된다.

u 옵션을 붙여서 upstream 설정도 같이해준다. 로컬 브랜치가 tracking 하는 리모트 브랜치다. 이 정보가 없으면 push를 할 때, 매번 로컬 브랜치와 리모트 브랜치를 적어줘야 한다.

#TIL #batch 5초 sleep

C:\> ping 127.0.0.1 -n 6 > nul

ping 사이에 1초 delay라서 5가 아닌 6을 넘긴다.

C:\> timeout /t 5

timeout 명령어를 사용해도 된다.

참고 - Sleeping in a batch file - stackoverflow.com