매개변수의 순서를 올바르게 식별하는 방법은 무엇입니까?

매개변수의 순서를 올바르게 식별하는 방법은 무엇입니까?

이것이 나의 사명이다. 작업은 입력 파일에서 n개의 가장 긴 라인을 출력하는 것입니다. n에 매개변수가 없으면 n의 기본값은 5입니다. 인수에 파일이 없으면 표준 입력이 사용됩니다. 파일이 2개 이상인 경우 이름 파일을 출력합니다. 출력 라인의 순서는 원본 파일의 순서와 동일해야 합니다. 선택적 매개변수를 처리하기 위해 여기에 질문을 했습니다.쉘 스크립트에서 선택적 입력을 처리하는 방법은 무엇입니까?

그러나 새로운 쉘 스크립트에서 또 다른 문제가 발생했습니다.

#!/bin/sh
while getopts “n” arg; do
  case $arg in
  n)
    # Check next positional parameter
    eval nextopt=\${$OPTIND}
    # existing or starting with dash?
    if [[ -n $nextopt && $nextopt != -* ]] ; then
      OPTIND=$((OPTIND + 1))
      level=$nextopt
    else
      level=5
    fi
    ;;
  esac
done

for name do
    if [ "$#" -gt 1 ]; then
        printf 'File: %s\n' "$name"
    fi
awk '{ print length(), NR, $0 | "sort -rn" }' $name | head -n $level | sed 's/[^ ]* //' | sort -n

done

저는 이렇게 운영해요

sh ex1.sh -n 10 unix1.txt unix1.1.txt

이것이 출력이다

File: -n
awk: can't open file -n
 source line number 1
File: 10
awk: can't open file 10
 source line number 1
File: unix1.txt
2 kbjkbkbbnbnmbnmnmmnbmnbmjbjkb
3 asjdsakdbakjsdbasbkj
4 asjdsakdbakjsdbasbkj
5 asjdsakdbakjsdbasbkj
10 ppûunsdj
11 tieutuvi
13 sdbhsdbjhdsvfdsvfgj
14 avavdvas
16 ffdsdfggdgdgdfgdfgdf112233
17 qwertyuiopsdfghjklxcvbnm,fghjk
File: unix1.1.txt
1 csdkbfsdk
2 fskjfnjkfnkjdsndjks
3 fsnjfnsjkf
4 snjfndsjknskjdfbnjksfdsfn
5 323124
6 jknjkkjnk4n4jn2
7 kjnjkb423
13 423b2j3kb4jk23bkb234kb32
14 234jb32jk43b
15 331

"-n"과 "10"은 파일이 아닙니다. 또 이렇게 달리면

sh ex1.sh -n unix1.txt unix1.1.txt

출력은 파일에서 가장 긴 5줄이어야 하지만 대신 다음과 같습니다.

File: -n
head: illegal line count -- unix1.txt
awk: can't open file -n
 source line number 1
File: unix1.txt
head: illegal line count -- unix1.txt
File: unix1.1.txt
head: illegal line count -- unix1.txt

그렇다면 이 문제를 어떻게 해결해야 할까요? 이것이 목표는 아니지만 효과가 있을 것입니다.

while getopts “n” arg; do
  case $arg in
  n)
    # Check next positional parameter
    eval nextopt=\${$OPTIND}
    # existing or starting with dash?
    if [[ -n $nextopt && $nextopt != -* ]] ; then
      OPTIND=$((OPTIND + 1))
      level=$nextopt
    else
      level=5
    fi
    ;;
  esac
done

awk '{ print length(), NR, $0 | "sort -rn" }' unix1.txt | head -n $level | sed 's/[^ ]* //' | sort -n

내가 달리면

sh ex1.sh -n 

나는 가지고있다

2 kbjkbkbbnbnmbnmnmmnbmnbmjbjkb
4 asjdsakdbakjsdbasbkj
5 asjdsakdbakjsdbasbkj
16 ffdsdfggdgdgdfgdfgdf112233
17 qwertyuiopsdfghjklxcvbnm,fghjk

또는

sh ex1.sh -n 10

나는 가지고있다

2 kbjkbkbbnbnmbnmnmmnbmnbmjbjkb
3 asjdsakdbakjsdbasbkj
4 asjdsakdbakjsdbasbkj
5 asjdsakdbakjsdbasbkj
10 ppûunsdj
11 tieutuvi
13 sdbhsdbjhdsvfdsvfgj
14 avavdvas
16 ffdsdfggdgdgdfgdfgdf112233
17 qwertyuiopsdfghjklxcvbnm,fghjk

어느 것이 정확합니까? 그리고, 매개변수에 파일이 없으면 표준입력을 사용하는데, 어떻게 처리하나요?

답변1

선택 -n항목에 매개변수가 필요하므로 가 필요합니다 getopts 'n:' arg.

옵션 매개변수는 에서 찾을 수 있습니다 $OPTARG.

OPTIND루프를 만지지 마십시오 while getopts.

루프가 끝난 후 shift "$(( OPTIND - 1 ))".this는 위치 인수에 파일 이름을 유지합니다.

그건,

#!/bin/sh

level=5
while getopts 'n:' arg; do
    case $arg in
      n) level=$OPTARG ;;
      *) echo 'Error in command line parsing' >&2
    esac
done

shift "$(( OPTIND - 1 ))"

for name do
    # stuff
done

다음으로 입력 파일이 없는 경우는 절대 처리하지 않습니다.

지정되지 않은 경우 다음 명령은 스크립트가 표준 입력을 파일 이름으로 사용하도록 합니다.

if [ "$#" -eq 0 ]; then
    # handle no filenames, for example:
    set -- /dev/stdin
fi

for name do
     # stuff
done

나머지는 여러분에게 맡기겠습니다(하지만 명확성을 위해 파이프라인에서 자체 단계로 이동하고 실행하는 것이 좋습니다) sort.awk

답변2

n에 매개변수가 없으면 n의 기본값은 5입니다.

getoptnot 을 사용하고 싶을 수도 있습니다 getopts. bash 내장 기능이 아니므로 매뉴얼 페이지를 읽고 참조하십시오.샘플 코드

이 예제 스크립트가 주어지면

#!/usr/bin/env bash

tmp=$(getopt -o n:: --long n:: -- "$@")

if [[ $? -ne 0 ]]; then 
    echo "usage: ..." >&2
    exit 1
fi

eval set -- "$tmp"

n=0

while :; do
    case "$1" in
        -n|--n) n=${2:-5}; shift 2 ;;
        --)     shift; break ;;
        *)      echo "error" >&2; exit 1 ;;
    esac
done

echo "n = $n"
echo "remaining args:"
printf "%s\n" "$@"

이중 콜론은 옵션이 선택적 매개변수를 취함을 나타냅니다. 다양한 방법으로 호출되면 어떤 일이 발생하는지 확인하세요.

$ bash sample.sh foo bar
n = 0
remaining args:
foo
bar
$ bash sample.sh -n foo bar
n = 5
remaining args:
foo
bar
$ bash sample.sh -n 10 foo bar
n = 5
remaining args:
10
foo
bar
$ bash sample.sh -n10 foo bar
n = 10
remaining args:
foo
bar
$ bash sample.sh --n foo bar
n = 5
remaining args:
foo
bar
$ bash sample.sh --n 10 foo bar
n = 5
remaining args:
10
foo
bar
$ bash sample.sh --n=10 foo bar
n = 10
remaining args:
foo
bar
$ bash sample.sh --n= foo bar
n = 5
remaining args:
foo
bar

매뉴얼 페이지를 주의 깊게 읽으십시오:

간단한 짧은 옵션은 " -" 뒤에 짧은 옵션 문자가 오는 것입니다. 옵션에 필수 인수가 있는 경우 옵션 문자 바로 뒤에 쓰거나 다음 인수로 쓸 수 있습니다(예: 명령줄에서 공백으로 구분). 옵션에 선택적 인수가 있는 경우 옵션 문자(있는 경우) 바로 뒤에 작성해야 합니다..

긴 옵션은 일반적 --으로 " "로 시작하고 그 뒤에 긴 옵션 이름이 옵니다. 옵션에 필수 인수가 있는 경우 긴 옵션 이름 바로 뒤에 =" "로 구분하여 작성하거나 다음 인수로 작성할 수 있습니다(예: 명령줄에서 공백으로 구분). 옵션에 선택적 매개변수가 있는 경우 긴 옵션 이름 바로 뒤에 =' '로 구분하여 작성해야 합니다.존재하는 경우( =뒤에 아무것도 없이 " "가 추가되면 인수가 없는 것처럼 해석됩니다. 이는 사소한 버그입니다. 버그를 참조하세요.)

관련 정보