파일 또는 stdin의 입력을 허용하는 스크립트를 작성하는 방법은 무엇입니까?


57

파일 이름 인수 또는 stdin의 입력을 허용하는 스크립트를 어떻게 작성할 수 있습니까?

예를 들어이 less방법을 사용할 수 있습니다 . 하나를 실행 less filename하고 동등하게 수행 할 수 있습니다 cat filename | less.

"상자 밖으로"쉽게 할 수있는 방법이 있습니까? 또는 바퀴를 다시 발명하고 스크립트에 약간의 논리를 작성해야합니까?


@PlasmaPower SU에 대한 주제가 주제 인 한 다른 SE 사이트에 문의 할 필요 는 없습니다 . 많은 SE 사이트가 겹칩니다. 일반적으로 질문이 주제를 벗어난 (이 경우 투표에 대한 투표) 주제이거나 주제가 많지만 응답이 많지 않은 경우 (이 경우 중재자가 중재자로 플래그를 지정해야 함)가 아닌 한 중복 사이트를 제안 할 필요는 없습니다 교차 포스트가 아닌주의 / 마이그레이션).

답변:


59

파일 인수가 스크립트의 첫 번째 인수 인 경우 인수 ( $1)가 있고 파일인지 테스트 하십시오. stdin에서 다른 읽기 입력-

따라서 스크립트에는 다음과 같은 내용이 포함될 수 있습니다.

#!/bin/bash
[ $# -ge 1 -a -f "$1" ] && input="$1" || input="-"
cat $input

예를 들어 다음과 같이 스크립트를 호출 할 수 있습니다

./myscript.sh filename

또는

who | ./myscript.sh

스크립트에 대한 설명을 편집하십시오 .

[ $# -ge 1 -a -f "$1" ]-하나 이상의 명령 행 인수 ( $# -ge 1) AND (-연산자)가 첫 번째 인수가 파일 인 경우 ( "$ 1"이 파일 인 경우 -f 테스트) 테스트 결과는 참입니다.

&&쉘 논리 AND 연산자입니다. 테스트가 참이면 파일 을 할당 input="$1"하고 cat $input출력합니다.

||쉘 논리 OR 연산자입니다. 테스트가 거짓이면 다음 명령 ||이 구문 분석됩니다. 입력은 "-"에 할당됩니다. 명령 cat -은 키보드에서 읽습니다.

요약하면, 스크립트 인수가 제공되고 파일 인 경우 변수 입력이 파일 이름에 지정됩니다. 유효한 인수가 없으면 cat은 키보드에서 읽습니다.


무엇을 && input="$1" || input="-" 하며 왜 test운영자 외부에 있습니까?
cmo

도움이 될만한 설명이있는 편집을 추가했습니다.
suspectus

스크립트에 여러 인수 ( $@)가있는 경우 어떻게합니까?
g33kz0r

12

read표준 입력에서 읽습니다. 파일 ( ./script <someinput) 또는 파이프 ( dosomething | ./script)를 통해 리디렉션하면 다르게 작동하지 않습니다.

입력의 모든 줄을 반복하기 만하면됩니다 (파일의 줄을 반복하는 것과 다르지 않습니다).

(샘플 코드, 한 줄만 처리)

#!/bin/bash

read var
echo $var

표준 입력의 첫 번째 줄을 통해 (에코 <또는 |) 에코합니다 .


감사! 다른 대답이 더 적합하기 때문에 선택합니다. 나는 다른 스크립트를 감싸고 있었고 모든 입력을받을 때까지 반복하고 싶지 않았습니다 (많은 입력이 될 수 있습니다 ... 낭비 적 일 것입니다).
gilad hoch

4

어떤 쉘을 사용할 계획인지 언급하지 않았으므로 bash를 가정 할 것입니다.하지만 쉘 전체에서 꽤 표준적인 것들입니다.

파일 인수

변수를 통해 인수에 액세스 할 수 있습니다 $1.- $n( $0프로그램을 실행하는 데 사용되는 명령을 반환합니다). cat구분 기호가있는 n 개의 파일을 구분 하는 스크립트가 있다고 가정 해보십시오 .

#!/usr/bin/env bash
#
# Parameters:
#    1:   string delimiter between arguments 2-n
#    2-n: file(s) to cat out
for arg in ${@:2} # $@ is the array of arguments, ${@:2} slices it starting at 2.
do
   cat $arg
   echo $1
done

이 경우 파일 이름을 cat로 전달합니다. 그러나 파일에서 데이터를 명시 적으로 쓰거나 다시 쓰지 않고 변환하려면 파일 내용을 변수에 저장할 수도 있습니다.

file_contents=$(cat $filename)
[...do some stuff...]
echo $file_contents >> $new_filename

stdin에서 읽기

stdin에서 읽는 한, 대부분의 쉘에는 표준이 read내장되어 있지만 프롬프트를 지정하는 방법에는 차이가 있습니다 (최소한).

배쉬 사람 페이지가 내장 명령 의 꽤 간결한 설명을 가지고 read,하지만 난 좋아 배쉬 해커 페이지를.

간단히:

read var_name

여러 변수

여러 변수를 설정하려면 다음과 같이 여러 매개 변수 이름을 제공하십시오 read.

read var1 var2 var3

read 그런 다음 stdin에서 하나의 단어를 각 변수에 배치하고 나머지 모든 단어를 마지막 변수에 덤프합니다.

λ read var1 var2 var3
thing1 thing2 thing3 thing4 thing5
λ echo $var1; echo $var2; echo $var3
thing1
thing2
thing3 thing4 thing5

변수보다 적은 단어가 입력되면 남은 변수는 비어 있습니다 (이전에 설정 한 경우에도).

λ read var1 var2 var3
thing1 thing2
λ echo $var1; echo $var2; echo $var3
thing1
thing2
# Empty line

프롬프트

-p프롬프트에 자주 플래그를 사용 합니다.

read -p "Enter filename: " filename

참고 : ZSH 및 KSH (및 기타)는 프롬프트에 다른 구문을 사용합니다.

read "filename?Enter filename: " # Everything following the '?' is the prompt

기본값

이것은 실제로 read속임수가 아니지만와 함께 많이 사용합니다 read. 예를 들면 다음과 같습니다.

read -p "Y/[N]: " reply
reply=${reply:-N}

기본적으로 변수 (답변)가 존재하면 자체를 반환하지만 비어 있으면 다음 매개 변수 ( "N")를 반환합니다.


4

가장 간단한 방법은 stdin을 직접 리디렉션하는 것입니다.

if [ "$1" ] ; then exec < "$1" ; fi

또는 더 간결한 형태를 선호하는 경우 :

test "$1" && exec < "$1"

이제 나머지 스크립트는 stdin에서 읽을 수 있습니다. 물론 파일 이름의 위치를로 하드 코딩하는 대신 고급 옵션 구문 분석을 사용하여 비슷하게 수행 할 수 있습니다 "$1".


exec여기서 우리가 원하지 않는 명령으로 인수를 실행하려고 시도합니다.
Suzana

@ Suzana_K : 여기와 같이 인수가 없을 때는 아닙니다. 이 경우 자식 프로세스가 아닌 셸 자체의 파일 설명자를 대체합니다.
R ..

if [ "$1" ] ; then exec < "$1" ; fi테스트 스크립트로 복사 했는데 명령이 알 수 없기 때문에 오류 메시지가 표시됩니다. 간결한 형태와 동일합니다.
Suzana

1
@Suzana_K : 어떤 쉘을 사용하고 있습니까? 이것이 사실이라면 POSIX sh 명령 / Bourne 쉘의 실제 구현이 아닙니다.
R ..

Linux Mint Qiana의 GNU bash 4.3.11
Suzana

3

이미 이런 식으로 동작하는 다른 것을 사용 (또는 연결 해제) "$@"

텍스트의 공백을 탭으로 대체하는 도구를 작성하려고한다고 가정 해 봅시다.

tr이 작업을 수행하는 가장 확실한 방법이지만 stdin 허용하므로 연결을 끊어야합니다 cat.

$ cat entab1.sh
#!/bin/sh

cat "$@"|tr -s ' ' '\t'
$ cat entab1.sh|./entab1.sh
#!/bin/sh

cat     "$@"|tr -s      '       '       '\t'
$ ./entab1.sh entab1.sh
#!/bin/sh

cat     "$@"|tr -s      '       '       '\t'
$ 

사용되는 도구가 이미 이런 식으로 동작하는 예를 들어, sed대신 다음 과 같이 다시 구현할 수 있습니다 .

$ cat entab2.sh
#!/bin/sh

sed -r 's/ +/\t/g' "$@"
$ 

3

당신은 또한 할 수 있습니다 :

#!/usr/bin/env bash

# Set variable input_file to either $1 or /dev/stdin, in case $1 is empty
# Note that this assumes that you are expecting the file name to operate on on $1
input_file="${1:-/dev/stdin}"

# You can now use "$input_file" as your file to operate on
cat "$input_file"

Bash의 깔끔한 매개 변수 대체 트릭은 this을 참조 하십시오 .


1
이건 끝내줘! 나는 사용 uglifyjs < /dev/stdin하고 있으며 훌륭하게 작동합니다!
fregante

0

간단하게 유지 하고이 코드를 사용할 수도 있습니다


이 코드 를 사용하여 스크립트 파일 pass_it_on.sh 를 만들면

#!/bin/bash

cat

당신은 실행할 수 있습니다

cat SOMEFILE.txt | ./pass_it_on.sh

stdin의 모든 내용은 단순히 화면으로 퍼져 나옵니다.


또는이 코드를 사용하여 stdin 사본을 파일에 보관 한 다음 화면에 뿌립니다.

#!/bin/bash

tmpFile=`mktemp`
cat > $tmpFile
cat $tmpFile    

여기에 더 읽기 쉬운 또 다른 예가 있습니다.

http://mockingeye.com/blog/2013/01/22/reading-everything-stdin-in-a-bash-script/

#!/bin/bash

VALUE=$(cat)

echo "$VALUE"

즐기세요

라미


0

POSIX를 준수하는 가장 간단한 방법은 다음과 같습니다.

file=${1--}

이는에 해당합니다 ${1:--}.

그런 다음 평소와 같이 파일을 읽으십시오.

while IFS= read -r line; do
  printf '%s\n' "$line" # Or: env POSIXLY_CORRECT=1 echo "$line"
done < <(cat -- "$file")
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.