배쉬 골프 팁


55

배쉬에서 골프를 치기 위해 어떤 일반적인 팁이 있습니까? 저는 Bash에 대해 다소 특정한 코드 골프 문제에 적용될 수있는 아이디어를 찾고 있습니다 (예 : "댓글 제거"는 답이 아닙니다). 답변 당 하나의 팁을 게시하십시오.

답변:


36

문서화되지 않았지만 레거시sh이전 버전과의 호환성을 위해 실행 한 모든 버전에서 작동합니다.

for루프를 사용하면 { }대신 사용할 수 있습니다 do done. 예 : 교체 :

for i in {1..10};do echo $i; done

와:

for i in {1..10};{ echo $i;}

이 쉘은 sh무엇이며이 for구문을 허용하는 쉘은 무엇 입니까? 에서 명시 적으로 허용됩니다 zsh.
mikeserv

@mikeserv 배쉬. sh슬프게도 인용이 없지만 이 구문이 일부 오래된 언어에서 허용되었고 Bash도 가능하기 때문에 어딘가에서 읽은 것을 기억합니다 .
Digital Trauma

아아 ... csh, 아마 그게 그 껍질에서 일한 방식 일 것입니다.
mikeserv

ksh93;{1..10}bashprintf %s\\n {1..10}
그건

1
for((;i++<10)){ echo $i;}보다 짧은for i in {1..10};{ echo $i;}
Evan Krall

29

산술 확장 $[…]대신 다음을 사용하십시오 $((…)).

bash-4.1$ echo $((1+2*3))
7

bash-4.1$ echo $[1+2*3]
7

산술 확장에서는 다음을 사용하지 않습니다 $.

bash-4.1$ a=1 b=2 c=3

bash-4.1$ echo $[$a+$b*$c]
7

bash-4.1$ echo $[a+b*c]
7

산술 확장은 인덱스 배열 첨자에서 수행되므로 다음 중 $어느 것도 사용 하지 마십시오 .

bash-4.1$ a=(1 2 3) b=2 c=3

bash-4.1$ echo ${a[$c-$b]}
2

bash-4.1$ echo ${a[c-b]}
2

산술 확장에서는 다음을 사용하지 않습니다 ${…}.

bash-4.1$ a=(1 2 3)

bash-4.1$ echo $[${a[0]}+${a[1]}*${a[2]}]
7

bash-4.1$ echo $[a[0]+a[1]*a[2]]
7

교체 while((i--))로, 어떤 작품, while[i--]또는 while $[i--]나를 위해 작동하지 않았다. GNU bash는 버전 4.3.46 (1)
글렌 데르-Pehrson

1
맞습니다, @ GlennRanders-Pehrson. 그것은 작동하지 않아야합니다.
manatwork

y=`bc<<<"($x*2.2)%10/1"`... bc정수가 아닌 계산 에 사용 하는 예 ... /1끝에있는 결과는 10 진수를 정수로 자릅니다.
roblogic

s=$((i%2>0?s+x:s+y))... bash 산술에서 삼항 연산자를 사용하는 예. 이보다 짧 if..then..else거나[ ] && ||
roblogic

1
@manatwork 감사합니다. 그들은 그것을 제거해야합니다. 나는 켜져 GNU bash, version 5.0.2(1)-release (x86_64-apple-darwin16.7.0)있고 그것은 내 안에 없습니다.
요나

19

함수를 정의하는 일반적이고 길고 지루한 방법은

f(){ CODE;}

이 녀석이 알다시피 , 당신은 절대적으로 전과 CODE뒤에 세미콜론이 필요 합니다.

이것은 @DigitalTrauma 에서 배운 약간의 트릭입니다 .

f()(CODE)

함수가 반환 된 후 변수 값의 변경 사항을 수행 할 필요가 없다면 ( 두 괄호가 본문을 서브 셸에서 실행 ) 두 문자가 짧아 작동합니다 .

따라 @ jimmy23013이 코멘트에 지적, 심지어 괄호가 불필요 할 수있다.

배쉬 참조 설명서는 다음과 같은 기능을 정의 할 수 있음을 보여줍니다 :

name () compound-command [ redirections ]

또는

function name [()] compound-command [ redirections ]

복합 명령을 할 수있다 :

  • 반복되는 구조 : until, while또는for
  • 조건부 구조 : if, case, ((...))또는[[...]]
  • 그룹화 된 명령 : (...)또는{...}

이는 다음이 모두 유효하다는 것을 의미합니다.

$ f()if $1;then $2;fi
$ f()($1&&$2)
$ f()(($1))                # This one lets you assign integer values

그리고 나는 빨판처럼 괄호를 사용했습니다 ...


2
f()while ... f()if ...및 기타 복합 명령을 사용할 수도 있습니다 .
jimmy23013

내가 f()CODE합법적 이라고 생각했기 때문에 이것은 나를 놀라게했다 . 그것은이 밝혀 f()echo hipdksh 같은 및 zsh을 법적 아니지만 bash는있다.
kernigh

1
for기본적으로 위치 : f()for x do : $x; done;set -x *;PS4=$* f "$@"또는 무언가 이기 때문에 특히 유용합니다 .
mikeserv

16

:아무 것도 수행하지 않는 명령이며 종료 상태는 항상 성공하므로 대신 사용할 수 있습니다 true.


서브 쉘과 파이핑을 사용하면 거의 같은 바이트 수를 사용하지만 파이핑이 더 실용적입니다.
ckjbgames 2016 년

5
당신이 할 때를 제외하고:(){:|:}
enedil

14

더 많은 팁

  1. 삼항 연산자 ((test)) && cmd1 || cmd2또는 [ test ] && cmd1 || cmd2을 최대한 많이 남용하십시오 .

    예 (길이 개수는 항상 맨 위 줄을 제외) :

    t="$something"
    if [ $t == "hi" ];then
    cmd1
    cmd2
    elif [ $t == "bye" ];then
    cmd3
    cmd4
    else
    cmd5
    if [ $t == "sup" ];then
    cmd6
    fi
    fi

    삼항 연산자 만 사용하면 다음과 같이 쉽게 단축 할 수 있습니다.

    t="$something"
    [ $t == "hi" ]&&{
    cmd1;cmd2
    }||[ $t == "bye" ]&&{
    cmd3;cmd4
    }||{
    cmd5
    [ $t == "sup" ]&&cmd6
    }

    nyuszika7h가 주석에서 지적 했듯이이 특정 예는 다음을 사용하여 더욱 단축 될 수 있습니다 case.

    t="$something"
    case $t in "hi")cmd1;cmd2;;"bye")cmd3;cmd4;;*)cmd5;[ $t == "sup" ]&&cmd6;esac
  2. 또한 가능한 괄호보다 괄호를 선호하십시오. 괄호는 단어가 아닌 메타 문자이므로 어떤 상황에서도 공백이 필요하지 않습니다. 중괄호 (예 : {})는 메타 문자가 아닌 예약어이므로 올바르게 구문 분석하려면 공백이 있어야하지만 메타 문자는 그렇지 않으므로 서브 쉘에서 최대한 많은 명령을 실행 해야합니다. 하위 쉘은 상위 환경에 영향을 미치지 않는다는 것을 알고 있으므로 모든 예제 명령을 하위 쉘에서 안전하게 실행할 수 있다고 가정하면 (어떤 경우에도 일반적이지 않음) 위의 코드를 다음과 같이 단축 할 수 있습니다 :

    t=$something
    [ $t == "hi" ]&&(cmd1;cmd2)||[ $t == "bye" ]&&(cmd3;cmd4)||(cmd5;[ $t == "sup" ]&&cmd6)

    또한 가능하지 않은 경우 괄호를 사용하면 여전히 일부를 줄일 수 있습니다. 명심해야 할 것은 정수에서만 작동한다는 것인데,이 예제 -eq에서는 정수를 사용할 수 없지만 정수 보다 사용하는 것이 훨씬 낫습니다 .

  3. 한 가지 더, 가능한 경우 따옴표를 피하십시오. 위의 조언을 사용하면 더 줄일 수 있습니다. 예:

    t=$something
    [ $t == hi ]&&(cmd1;cmd2)||[ $t == bye ]&&(cmd3;cmd4)||(cmd5;[ $t == sup ]&&cmd6)
  4. 테스트 조건에서는 몇 가지 예외를 제외하고 단일 괄호보다 이중 괄호를 선호합니다. 두 문자를 무료로 삭제하지만 경우에 따라 강력하지 않습니다 (Bash 확장입니다-아래 예제 참조). 또한 double 대신 single equals 인수를 사용하십시오. 떨어 뜨릴 자유 캐릭터입니다.

    [[ $f == b ]]&&: # ... <-- Bad
    [ $f == b ]&&: # ... <-- Better
    [ $f = b ]&&: # ... <-- Best.  word splits and pathname-expands the contents of $f.  Esp. bad if it starts with -

    특히 널 출력 또는 정의되지 않은 변수를 확인할 때이주의 사항에 유의하십시오.

    [[ $f ]]&&:    # double quotes aren't needed inside [[, which can save chars
    [ "$f" = '' ]&&: <-- This is significantly longer
    [ -n "$f" ]&&:

    모든 기술 에서이 특정 예는 case... 로 가장 좋습니다 in.

    t=$something
    case $t in hi)cmd1;cmd2;;bye)cmd3;cmd4;;*)cmd5;[ $t == sup ]&&cmd6;esac

따라서이 게시물의 도덕은 다음과 같습니다.

  1. 부울 연산자를 가능한 많이 남용하고 항상if / if-else/ etc 대신 사용하십시오 . 구조물.
  2. 괄호는 예약어가 아닌 메타 문자이므로 가능한 한 괄호를 사용하고 서브 쉘에서 최대한 많은 세그먼트를 실행하십시오.
  3. 물리적으로 가능한 한 따옴표를 피하십시오.
  4. 체크 아웃 case... in, 특히 문자열 일치에서 상당히 많은 바이트를 절약 할 수 있습니다.

추신 : 컨텍스트와 상관없이 Bash에서 인식되는 메타 문자 목록은 다음과 같습니다 (단어를 분리 할 수 ​​있음).

&lt; &gt; ( ) ; & | &lt;space&gt; &lt;tab&gt;

편집 : manatwork가 지적했듯이 이중 괄호 테스트는 정수에 대해서만 작동합니다. 또한 간접적으로 ==운영자 주변에 공백이 있어야한다는 것을 알았습니다 . 위의 내 게시물을 수정했습니다.

또한 각 세그먼트의 길이를 다시 계산하기에는 너무 게 으르므로 간단히 제거했습니다. 필요한 경우 온라인으로 문자열 길이 계산기를 쉽게 찾을 수 있어야합니다.


죄송합니다. 심각한 오류가 있습니다. [ $t=="hi" ]로 구문 분석되므로 항상 0으로 평가됩니다 [ -n "STRING" ]. (($t=="hi"))산술 평가에서 문자열이 정수로 강제 적용되므로 $ t에 숫자가 아닌 값이있는 한 항상 0으로 평가됩니다. 일부 테스트 사례 : pastebin.com/WefDzWbL
manatwork 2013

@manatwork 감사합니다. 그에 따라 업데이트하겠습니다.
Isiah Meadows

여기서 사용하는 case것이 더 짧습니다. 또한 앞에 공백이 필요하지 않지만 }이후 에는 공백이 필요합니다 {.
nyuszika7 시간

1
=덜 견고 ==합니까? =POSIX에 의해 요구되고 ==그렇지 않습니다.
Dennis

1
질문은 답변 당 하나의 팁을 요구합니다 ...
Toby Speight

7

대신에 grep -E, grep -F, grep -r, 사용 egrep, fgrep, rgrep, 두 개의 문자를 저장. 더 짧은 것은 더 이상 사용되지 않지만 정상적으로 작동합니다.

(응답 당 하나의 팁을 요청했습니다!)


1
너무 나쁜 더가 없습니다 Pgrep위해 grep -P. pgrep프로세스를 조회하는 데 사용 되는와 혼동되는 방법을 알았 습니다.
nyuszika7h

1
@ nyuszika7h 개인적 grep -o으로 많이 사용

공간을 포함하여 3을 저장하지 않습니까?
ckjbgames

7

배열의 요소 0은 변수 이름으로 만 액세스 할 수 있으며 인덱스 0을 명시 적으로 지정하면 5 바이트를 절약 할 수 있습니다.

$ a=(code golf)
$ echo ${a[0]}
code
$ echo $a
code
$ 

7

파이프 라인에서 변수의 내용을 다음 프로세스의 STDIN으로 전달해야하는 경우 변수를 파이프 라인에 에코하는 것이 일반적입니다. 그러나 <<< bash here string을 사용하면 동일한 결과를 얻을 수 있습니다 .

$ s="code golf"
$ echo "$s"|cut -b4-6
e g
$ cut -b4-6<<<"$s"
e g
$ 

2
우리가 골프를하고 있기 때문에 s=code\ golf, echo $s|그리고 <<<$s(염두에두고하는 등, 더 반복 공백이없는 경우에만 때문에 뒤의 두 작품).
Dennis

6

피하십시오 $( ...command... ), 하나의 문자를 저장하고 동일한 작업을 수행하는 대안이 있습니다.

` ...command... `

9
$( )중첩 된 명령 대체가있는 경우 가끔 필요합니다. 그렇지 않으면 당신은 내부를 탈출해야합니다``
Digital Trauma

1
이들은 기술적으로 다른 일 $()을합니다 scp. 예를 들어 대상 컴퓨터 대신 내 컴퓨터에서 대체를 실행하려고 할 때 대신 백틱을 사용해야했습니다 . 대부분의 경우 동일합니다.
undergroundmonorail

2
@undergroundmonorail : 백틱이 필요 하지 않습니다 . 그들이 할 수있는 모든 것, $()당신이 제대로 인용하면 할 수 있습니다. (뒤죽박죽이 $아닌 머뭇 거림에서 살아 남기 위해 당신의 명령이 필요하지 않는 한 ). 그 안에 물건을 인용하는 데 미묘한 차이점이 있습니다. mywiki.wooledge.org/BashFAQ/082 는 몇 가지 차이점을 설명합니다. 골프를 타지 않는 한 백틱을 사용하지 마십시오.
Peter Cordes

@PeterCordes 내가 거기 확신 했다 방법이 있지만이 시간에 시도 모든 것이 작동하지 않았다. 백틱이 최상의 솔루션이 아니더라도, 내가 가지고있는 유일한 솔루션이기 때문에 나는 그들에 대해 알고 기뻤습니다. ¯ \ _ (ツ) _ / ¯
undergroundmonorail

@DigitalTrauma 중첩 샘플 : echo `bc <<<"\`date +%s\`-12"`... (주석에 백틱이 포함 된 샘플을 게시하기는 어렵습니다!;)
F. Hauri

6

사용 if그룹 명령에

이 팁 과 비교할 때 if전혀 제거 하지 않는 경우와 같이 매우 드문 경우에만 작동합니다 if.

로 끝나는 명령 그룹이있는 경우 다음 if과 같이하십시오.

a&&{ b;if c;then d;else e;fi;}
a&&(b;if c;then d;else e;fi)

if대신 조건에서 명령을 랩핑 할 수 있습니다 .

a&&if b;c;then d;else e;fi

또는 함수가 다음으로 끝나는 경우 if:

f(){ a;if b;then c;else d;fi;}

중괄호를 제거 할 수 있습니다.

f()if a;b;then c;else d;fi

1
[test] && $if_true || $else이 함수에서 삼항 연산자 를 사용하고 일부 바이트를 저장할 수 있습니다.
ckjbgames

또한, 주변 공간을 필요로하지 않습니다 &&||
roblogic

6

(( ... ))조건에 산술 사용

다음을 교체 할 수 있습니다.

if [ $i -gt 5 ] ; then
    echo Do something with i greater than 5
fi

으로, ~에 의하여

if((i>5));then
    echo Do something with i greater than 5
fi

(참고 : 뒤에 공백이 없습니다 if)

또는

((i>5))&&{
    echo Do something with i greater than 5
}

... 또는 하나의 명령 만

((i>5))&&echo Echo or do something with i greater than 5

또한 : 산술 구문에서 변수 설정 숨기기 :

((i>5?c=1:0))&&echo Nothing relevant there...
# ...
((c))&&echo Doing something else if i was greater than 5

또는 동일

((c=i>5?c=0,1:0))&&echo Nothing relevant there...
# ...
((c))&&echo Doing something else if i was greater than 5

... 여기서 i> 5이면 c = 1 (0이 아님)


[ ]대신을 사용하여 2 바이트를 절약 할 수 (())있습니다.
ckjbgames

@ckjbgames 확실합니까?! Wich bash 버전을 사용하고 있습니까?
F. Hauri

@ FHauri 바이트 단위로 거의 동일하다고 생각합니다.
ckjbgames

@ckjbgames [ ]변수를 사용하려면 달러 기호가 필요합니다. 을 사용하여 길이가 같거나 작은 방법으로 동일한 작업을 수행하는 방법을 알 수 없습니다 [ ].
F. Hauri

보너스 팁 : for 루프의 첫 줄이로 시작하면 ((...))줄 바꿈이나 공백이 필요하지 않습니다. 예 : for((;10>n++;)){((n%3))&&echo $n;} 온라인으로 사용해보십시오!
primo December

6

무한 루프에 대한 짧은 구문 ( break또는 exit문 으로 이스케이프 할 수 있음 )은 다음과 같습니다.

for((;;)){ code;}

이것은 while true;및 보다 짧습니다 while :;.

필요하지 않은 경우 break( exit이탈하는 유일한 방법으로) 대신 재귀 함수를 사용할 수 있습니다.

f(){ code;f;};f

중단이 필요하지만 종료가 필요하지 않고 루프 외부에서 변수 수정을 수행 할 필요가없는 경우 본문 주위에 괄호를 사용하여 재귀 함수 사용할 수 있습니다. 이 함수는 서브 쉘에서 함수 본문을 실행합니다.

f()(code;f);f

6

한 줄 for루프

범위 확장과 연결된 산술 표현식은 범위의 각 항목에 대해 평가됩니다. 예를 들면 다음과 같습니다.

: $[expression]{0..9}

expression10 회 평가 됩니다.

이것은 종종 등가 for루프 보다 상당히 짧습니다 .

for((;10>n++;expression with n)){ :;}
: $[expression with ++n]{0..9}

command not found 오류가 마음에 들지 않으면 inital을 제거 할 수 있습니다 :. 10보다 큰 반복의 경우 문자 범위를 사용할 수도 있습니다 (예 : {A..z}58 회 반복).

실용적인 예로, 다음 두 가지 모두 첫 번째 삼각 숫자를 각각 자체적으로 생성합니다.

for((;50>d++;)){ echo $[n+=d];} # 31 bytes
printf %d\\n $[n+=++d]{A..r}    # 28 bytes

또한 거꾸로 반복 할 수 있습니다.for((;0<i--;)){ f;}
roblogic

5

인수를 반복

에서 언급 한 바와 같이 는 "foo는 표시 줄에 ..."부분없이 루프 "를"배쉬in "$@;"의는 for x in "$@;"중복입니다.

보낸 사람 help for:

for: for NAME [in WORDS ... ] ; do COMMANDS; done
    Execute commands for each member in a list.

    The `for' loop executes a sequence of commands for each member in a
    list of items.  If `in WORDS ...;' is not present, then `in "$@"' is
    assumed.  For each element in WORDS, NAME is set to that element, and
    the COMMANDS are executed.

    Exit Status:
    Returns the status of the last command executed.

예를 들어, 위치 인수가 지정된 모든 숫자를 Bash 스크립트 또는 함수로 제곱하려면이 작업을 수행 할 수 있습니다.

for n;{ echo $[n*n];}

온라인으로 사용해보십시오!


5

고양이의 대안

파일을 읽고 다른 곳에서 사용하려고한다고 가정하십시오. 당신이 할 수있는 일은 :

echo foo `cat bar`

의 내용이있는 경우 bar였다 foobar,이 인쇄 것입니다 foo foobar.

그러나이 방법을 사용하는 경우 3 바이트를 절약 할 수있는 대안이 있습니다.

echo foo `<bar`

1
<bar자체적으로 작동하지 않지만 백틱에 배치 하는 이유 는 무엇입니까?
Kritixi Lithos

@Cowsquack 예. 는 <명령에 파일을두고 있지만,이 경우에는 인해 특질에 표준 출력으로 넣습니다. 백틱은 이것을 함께 평가합니다.
Okx

이외의 표준 입력에서 읽는 더 짧은 방법이 `cat`있습니까?
Joel

4

사용 [대신 [[하고 test가능하면

예:

[ -n $x ]


비교 =대신 사용==

예:

[ $x = y ]

등호 주위에 공백 이 있어야합니다 . 그렇지 않으면 작동하지 않습니다. ==내 테스트 에 따라 동일하게 적용됩니다 .


3
[대이 [[필요한 따옴표의 양에 따라 달라질 수 있습니다 : pastebin.com/UPAGWbDQ
manatwork

@manatwork 좋은 지적입니다.
nyuszika7 시간

1
일반 규칙 : [... ]== /bin/test하지만 [[... ]]! = /bin/test하나는 선호해서는 안 [... ]이상 [[... ]]codegolf의 외부
고양이

4

대안 head

line보다 3 바이트 짧은 head -1,하지만되고있다 되지 않습니다 .

sed q보다 2 바이트 짧습니다 head -1.

sed 9q보다 1 바이트 짧습니다 head -9.


1
하지만 운명 , 우리는 여전히 잠시 동안 사용할 수 있습니다 line에서 폴더의 유틸리티 - 리눅스 한 줄을 읽어 패키지로 제공된다.
manatwork

4

tr -cd 보다 짧다 grep -o

예를 들어, 공백을 계산해야하는 경우 grep -o <char>(일치 된 항목 만 인쇄)는 10 바이트를 제공하고 tr -cd <char>(보충 삭제 <char>)는 9를 제공합니다.

# 16 bytes
grep -o \ |wc -l
# 15 bytes
tr -cd \ |wc -c

( 소스 )

둘 다 약간 다른 출력을 제공합니다. grep -o행으로 구분 된 결과를 반환 tr -cd하는 동시에 모두 같은 행에 결과를 제공하므로 tr항상 선호되는 것은 아닙니다.


4

파일명 단축

최근의 과제에서 파일을 읽으려고 /sys/class/power_supply/BAT1/capacity했지만 /*/*/*/*/capac*y다른 파일이 해당 형식으로 존재하지 않기 때문에 단축 될 수 있습니다 .

예를 들어, foo/파일을 포함 하는 디렉토리 가 있고 파일 foo, bar, foobar, barfoo을 참조하려는 경우 바이트를 저장하는 데 foo/barfoo사용할 수 있습니다 foo/barf*.

*"무엇"을 나타내며, 정규식에 해당합니다 .*.


3

:대신 명령에 파이프를 사용하십시오 /dev/null. :내장 된 모든 입력을 먹을 것이다.


2
아니요, 대부분의 경우 SIGPIPE로 프로그램이 중단됩니다. echo a|tee /dev/stderr|:아무것도 인쇄하지 않습니다.
jimmy23013

경쟁 echo a|tee /dev/stderr|:이 있습니다. 내 컴퓨터에 인쇄를했지만 다른 곳에서는 SIGPIPE가 티를 먼저 죽일 수 있습니다. 버전에 따라 다를 수 있습니다 tee.
kernigh

예, 그것은 SIGPIPE 문제입니다. tee >(:) < <(seq 1 10)작동하지만 작동 tee /dev/stderr | :하지 않습니다. 심지어 a() { :;};tee /dev/stderr < <(seq 1 10)| a아무것도 인쇄되지 않습니다.
F. Hauri

@ user16402-내 구매에 fccing 이름이 있어야합니다 ... 어쨌든 :본질적인 것은 전혀 먹지 않습니다 ... 콜론에 입력을 가하면 파이프를 홍수로 넘칠 수 있지만 리디렉션을 플로팅 할 수는 있습니다 ... 콜론에 의해, 또는 그것과 함께 프로세스를 포기하거나 ... :| while i>&$(($??!$?:${#?})) command shit; do [ -s testitsoutput ]; done의사 제안이 적용됩니다 ... 또한, 당신은 나처럼 거의 유령 같은 것을 알고 있습니까? ... 모든 비용을 피하십시오< <(psycho shit i can alias to crazy math eat your world; okay? anyway, ksh93 has a separate but equal composite char placement)
mikeserv

3

split의 섹션으로 분할 입력을위한 또 다른 (사용되지 않는,하지만 아무도 관심 없음) 구문은 N라인을 각각 : 대신 split -lN사용할 수있는 split -Nsplit -9.


3

테스트 확장

본질적으로 쉘은 일종의 매크로 언어이거나 적어도 하이브리드 또는 어떤 종류입니다. 모든 명령 줄은 기본적으로 구문 분석 / 입력 부분과 확장 / 출력 부분의 두 부분으로 나눌 수 있습니다.

첫 번째 부분은 가장 단순하기 때문에 대부분의 사람들이 집중하는 것입니다. 두 번째 부분은 많은 이제까지도 잘 이해하려고 노력하고 사람들이 일을 좋아하는 말을 왜 피하는 것입니다 eval악한당신의 확장을 인용 항상 사람들이 첫 번째 동일하게 첫 번째 부분의 결과를 원하는 -. 괜찮습니다. 불필요하게 긴 코드 분기와 수많은 외부 테스트로 이어집니다.

확장은 자체 테스트 입니다. ${param[[:]#%+-=?]word}형태는 매개 변수의 내용을 확인하기 충분하다 중첩 가능한, 그리고 모든 평가를 기반으로하는 NUL - 대부분의 사람들이 어쨌든 테스트의 기대이다. +루프에서 특히 유용 할 수 있습니다.

r()while IFS= read -r r&&"${r:+set}" -- "$@" "${r:=$*}";do :;done 2>&-

IFS=x
printf %s\\n some lines\ of input here '' some more|{ r;echo "$r"; }

somexlines ofxinputxhere

... read빈 줄 을 당기지 않으면 "${r:+set}"확장되고 "set"위치가 $r추가됩니다. 빈 줄이 때 read, $r비어 "${r:+set}"에 확장 ""- 잘못된 명령이다. 커맨드 라인이 확장되기 때문에 그러나 전에"" 널 명령을 검색하고, "${r:=$*}"상기 첫 번째 바이트에 연접 positionals 모든 값 얻어 $IFS도있다. 쉘이 입력 의 다음 ewline을 넘어 버퍼링 하는 것은 불법이기 때문에 다음 입력 단락을 얻기 위해 다른 값을 갖는 복합 명령 r()에서 다시 호출 될 수 있습니다 .|{;}$IFSread\n


3

꼬리 재귀를 사용하여 루프를 짧게 만듭니다.

메모리 / PID 사용량이 아닐 수도 있지만 동작은 동일합니다.

while :;do body; done
f()(body;f);f
body;exec $0
body;$0

그리고 이것들은 대략 동등합니다 :

while condition; do body; done
f()(body;condition&&f);f
body;condition&&exec $0
body;condition&&$0

(기술적으로 마지막 3 개는 항상 적어도 한 번 본문을 실행합니다)

사용 $0하려면 스크립트가 bash 프롬프트에 붙여지지 않은 파일에 있어야합니다.

결국 스택이 오버플로 될 수 있지만 일부 바이트를 절약 할 수 있습니다.


3

때로는 expr일반적인 산술 대신 간단한 산술 표현식의 결과를 표시 하기 위해 내장 을 사용하는 것이 더 짧은 경우가 있습니다 echo $[ ]. 예를 들면 다음과 같습니다.

expr $1 % 2

다음보다 1 바이트 더 짧습니다.

echo $[$1%2]

2

출력 라인을 생성하는 pwd대신 사용echo

stdout에 줄을 써야하지만 내용에 신경 쓰지 않고 대답을 쉘 내장으로 제한하고 싶습니까? pwd보다 짧은 바이트 echo입니다.


2

문자열을 인쇄 할 때는 따옴표를 생략 할 수 있습니다.

echo "example"
echo example

SM-T335 LTE, Android 5.1.1의 출력 :

u0_a177@milletlte:/ $ echo "example"
example
u0_a177@milletlte:/ $ echo example
example

2

비 연속 배열 항목을 할당 할 때 연속 청크의 연속 인덱스를 건너 뛸 수 있습니다.

bash-4.4$ a=([1]=1 [2]=2 [3]=3 [21]=1 [22]=2 [23]=3 [31]=1)

bash-4.4$ b=([1]=1 2 3 [21]=1 2 3 [31]=1)

결과는 같습니다 :

bash-4.4$ declare -p a b
declare -a a=([1]="1" [2]="2" [3]="3" [21]="1" [22]="2" [23]="3" [31]="1")
declare -a b=([1]="1" [2]="2" [3]="3" [21]="1" [22]="2" [23]="3" [31]="1")

에 따르면 man bash:

배열은 name = (value 1 ... value n ) 형식의 복합 지정을 사용하여 지정되며 , 각 은 [ subscript ] = string 형식 입니다. 인덱스 배열 할당에는 string 외에 다른 것이 필요하지 않습니다 . 인덱스 배열에 할당 할 때 선택적 대괄호와 아래 첨자가 제공되면 해당 인덱스가 할당됩니다. 그렇지 않으면 할당 된 요소의 인덱스는 명령문에 의해 할당 된 마지막 인덱스에 1을 더한 것입니다.


추가하는 데 도움이 : 초기화되지 않은 요소는 산술 확장에서는 0으로 확장되고 다른 확장에서는 ""로 확장됩니다.
디지털 외상

2

문자열에서 첫 단어를 인쇄

문자열이 변수에 a있고 이스케이프 및 형식 문자 ( \%)를 포함하지 않는 경우 다음을 사용하십시오.

printf $a

그러나 결과를 인쇄하는 대신 변수에 저장해야하는 경우 다음 코드보다 길 수 있습니다.

x=($a)
$x

1

1 개의 for명령어로 2 개의 내장 루프 수행 :

for ((l=i=0;l<=99;i=i>98?l++,0:++i)) ;do
    printf "I: %2d, L: %2d\n" $i $l
done |
    tee >(wc) | (head -n4;echo ...;tail -n 5)
I:  0, L:  0
I:  1, L:  0
I:  2, L:  0
I:  3, L:  0
...
I: 96, L: 99
I: 97, L: 99
I: 98, L: 99
I: 99, L: 99
  10000   40000  130000

1

인용 문자열 할당 및 인쇄

따옴표 붙은 문자열을 변수에 할당하고 해당 변수의 값을 인쇄하려면 일반적인 방법은 다음과 같습니다.

a="Programming Puzzles & Code Golf";echo $a

경우 a이전에 해제했다, 이것은 단축 할 수있다 :

echo ${a=Programming Puzzles & Code Golf}

a이전에 설정된 경우 대신 사용해야합니다.

echo ${a+Programming Puzzles & Code Golf}

문자열에 따옴표가 필요한 경우 (예 : 공백 포함)에만 유용합니다. 따옴표없이 a=123;echo $a짧습니다.


${a+foo}설정하지 않았습니다 a.
GammaFunction
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.