파일의 줄을 명령의 인수로 어떻게 사용합니까?


158

인수를 foo.txt지정 하는 파일이 있습니다.N

arg1
arg2
...
argN

내가 명령에 전달해야 my_command

파일의 줄을 명령의 인수로 어떻게 사용합니까?


10
"인수", 복수 또는 "인수", 단일? 허용되는 답변은 본문 텍스트가 요구하는 단일 인수의 경우에만 정확하지만 주제가 문의하는 것처럼 보이는 다중 인수의 경우에는 맞지 않습니다.
Charles Duffy

아래의 4 가지 답변은 일반적으로 동일한 결과를 갖지만 의미가 약간 다릅니다. 이제 왜 내가 bash 스크립트 작성을 중단했는지 기억합니다. : P
Navin

답변:


236

쉘이 bash (다른 것들 중에서)라면 바로 가기는 $(cat afile)입니다 $(< afile).

mycommand "$(< file.txt)"

'명령 대체'섹션의 bash 매뉴얼 페이지에 설명되어 있습니다.

또는 stdin에서 명령을 읽도록하십시오. mycommand < file.txt


11
pedantic하기 위해, 그것은 <연산자 를 사용하는 지름길이 아닙니다 . 이것은 쉘 자체가 cat리디렉션 속성에 대해 바이너리를 실행하는 대신 리디렉션을 수행한다는 것을 의미합니다 .
lstyls

2
커널 설정이므로 커널을 다시 컴파일해야합니다. 또는 xargs 명령
glenn jackman을

3
@ykaner가 없으면 "$(…)"의 내용이 인수가 아닌 file.txt의 표준 입력으로 전달 되기 때문 mycommand입니다. "$(…)", 명령을 실행하고 출력을 문자열로 제공합니다 . 여기서 "명령"은 파일 만 읽지 만 더 복잡 할 수 있습니다.
törzsmókus

3
따옴표를 잃지 않으면 그것은 나를 위해 작동하지 않습니다. 따옴표를 사용하면 전체 파일을 1 개의 인수로 사용합니다. 따옴표가 없으면 각 줄을 별도의 인수로 해석합니다.
Pete

1
@LarsH 당신은 절대적으로 맞습니다. 그것을 넣는 것이 덜 혼란스러운 방법입니다. 감사합니다.
lstyls

37

이미 언급했듯이 백틱 또는을 사용할 수 있습니다 $(cat filename).

언급되지 않았으며 주목해야 할 것은 쉘이 공백에 따라 해당 파일의 내용을 분리하고 명령에 찾은 각 "단어"를 인수로 제공한다는 점을 기억해야한다는 것입니다. 또한 공백, 이스케이프 시퀀스 등을 포함 할 수 있도록 명령 줄 인수를 따옴표로 묶을 수는 있지만 파일을 읽더라도 동일한 작업을 수행하지는 않습니다. 예를 들어 파일에 다음이 포함 된 경우

a "b c" d

당신이 얻을 인수는 다음과 같습니다

a
"b
c"
d

각 줄을 인수로 가져 오려면 while / read / do 구문을 사용하십시오.

while read i ; do command_name $i ; done < filename

나는 당신이 bash를 사용하고 있다고 가정하고 언급했다. 나는 다른 쉘이 있다는 것을 알고 있지만, 내가 작업 한 거의 모든 * nix 기계는 bash를 실행하거나 동등한 것을 실행했습니다. IIRC에서이 구문은 ksh 및 zsh에서 동일하게 작동해야합니다.

1
read -r백 슬래시 이스케이프 시퀀스를 확장하지 않으려면 읽어야합니다 . 특히 전달하는 인수가 파일 이름과 같이 문자 그대로의 개행 문자를 포함 할 수있는 경우 NUL은 개행 문자보다 사용하기에 더 안전합니다. 또한 IFS를 지우지 않고에서 앞뒤 공백을 암시 적으로 얻을 수 있습니다 i.
찰스 더피

18
command `< file`

stdin에서 명령에 파일 내용을 전달하지만 줄 바꿈을 제거하므로 각 줄을 개별적으로 반복 할 수 없습니다. 이를 위해 'for'루프를 사용하여 스크립트를 작성할 수 있습니다.

for line in `cat input_file`; do some_command "$line"; done

또는 (여러 줄 변형) :

for line in `cat input_file`
do
    some_command "$line"
done

또는 ( $()대신에 여러 줄 변형 ``) :

for line in $(cat input_file)
do
    some_command "$line"
done

참고 문헌 :

  1. 루프 구문 : https://www.cyberciti.biz/faq/bash-for-loop/

또한 < file백틱을 넣으면 실제로 리디렉션을 command전혀 수행하지 않습니다 .
Charles Duffy

3
(이 문제를지지 한 사람들이 실제로 테스트 했습니까? bash 또는 POSIX sh에서 command `< file` 작동하지 않습니다 . zsh는 다른 문제이지만이 질문의 핵심은 아닙니다.)
찰스 더피

@CharlesDuffy 작동하지 않는 방법에 대해 더 구체적으로 설명 할 수 있습니까?
mwfearnley

@CharlesDuffy 이것은 bash 3.2 및 zsh 5.3에서 작동합니다. 이것은 sh, ash 및 dash에서는 작동하지 않지만 $ (<file)에서는 작동하지 않습니다.
Arnie97

1
@mwfearnley, 그 특이성을 기꺼이 제공합니다. 목표는 라인을 반복하는 것입니다. Hello World한 줄에 두십시오 . 먼저 실행 된 some_command Hello다음 some_command World, 그렇지 않은 some_command "Hello World" 또는을 볼 수 some_command Hello World있습니다.
찰스 더피

15

당신은 백틱을 사용하여 그렇게합니다 :

echo World > file.txt
echo Hello `cat file.txt`

4
이 만들지 않습니다 그것이 인용되지 않기 때문에 당신이 방출되는 경우에 따라서, 문자열 분할에 그것의 제목을 - 인수를 첫 번째 단계에서, 두 번째 명령에 전달 적어도 네 개의 별도의 인수를 얻을 것 - 가능성 로 더 의 파일의 이름을 확장 할 현재 디렉토리에 제시한다. echo "Hello * Starry * World" > file.txt*
Charles Duffy

3
... 그런 확장을 실행하기 때문에 파일의 내용을 정확하게 방출하지 않습니다 . 그리고 그것은 명령 치환 작업을 수행 있기 때문에, 그것은 매우 비효율적 - 실제로있어 fork()다음의 표준 출력에 부착 된 FIFO와 서브 쉘 떨어져 보내고 호출 /bin/cat한 후 FIFO를 통해 출력을 읽고, 그 서브 쉘의 자식으로; $(<file.txt)서브 쉘이나 FIFO를 사용하지 않고 파일 내용을 bash로 직접 읽는 것과 비교합니다 .
찰스 더피

11

가능한 모든 명령 줄 인수 (공백이있는 값, 줄 바꿈이있는 값, 리터럴 따옴표 문자가있는 값, 인쇄 할 수없는 값, glob 문자가있는 값 등)에 대해 강력한 방법 으로이 작업을 수행하려면 약간의 가치가 있습니다. 더 흥미로운.


인수 배열이 주어지면 파일에 쓰려면 다음을 수행하십시오.

printf '%s\0' "${arguments[@]}" >file

... 교체 "argument one", "argument two"적절하게, 등.


해당 파일에서 읽고 해당 내용을 사용하려면 (bash, ksh93 또는 배열이있는 다른 최신 쉘) :

declare -a args=()
while IFS='' read -r -d '' item; do
  args+=( "$item" )
done <file
run_your_command "${args[@]}"

해당 파일에서 읽고 내용을 사용하려면 (배열이없는 쉘에서) 로컬 명령 줄 인수 목록을 덮어 쓰므로 함수 내부에서 수행하는 것이 가장 좋습니다. 따라서 함수의 인수를 덮어 쓰지 않아야합니다. 전체 목록) :

set --
while IFS='' read -r -d '' item; do
  set -- "$@" "$item"
done <file
run_your_command "$@"

그 주 -d(다른 끝 (end-of-line) 구분 기호를 사용할 수 있도록)는 비 POSIX 확장하고, 배열이없는 쉘은 또한 그것을 지원하지 않을 수 있습니다. 이 경우 NUL로 구분 된 내용을 eval안전한 형식 으로 변환하기 위해 쉘이 아닌 언어를 사용해야 할 수도 있습니다 .

quoted_list() {
  ## Works with either Python 2.x or 3.x
  python -c '
import sys, pipes, shlex
quote = pipes.quote if hasattr(pipes, "quote") else shlex.quote
print(" ".join([quote(s) for s in sys.stdin.read().split("\0")][:-1]))
  '
}

eval "set -- $(quoted_list <file)"
run_your_command "$@"

6

다음은 파일의 내용을 명령의 인수로 전달하는 방법입니다.

./foo --bar "$(cat ./bar.txt)"

1
이것은 (비교적 $(<bar.txt)bash와 같은 쉘을 적절한 확장으로 사용하는 경우) 와 실질적으로 덜 효율적이지만 실질적으로 덜 효율적 입니다. $(<foo)특별한 경우입니다 :에서 사용되는 일반 명령 대체와 달리 $(cat ...)서브 쉘을 포크하지 않아서 많은 오버 헤드를 피할 수 있습니다.
Charles Duffy

3

당신이해야 할 모든 arguments.txt내용과 파일을 설정하는 것 입니다

arg1
arg2
argN

로에게 my_command arg1 arg2 argN당신은 간단하게 사용할 수 있습니다 xargs:

xargs -a arguments.txt my_command

당신은 추가적인 정적 인수를 넣을 수 있습니다 xargs처럼 호출 xargs -a arguments.txt my_command staticArg하는 호출my_command staticArg arg1 arg2 argN


1

내 bash 쉘에서 다음은 매력처럼 작동했습니다.

cat input_file | xargs -I % sh -c 'command1 %; command2 %; command3 %;'

여기서 input_file은

arg1
arg2
arg3

분명,이 당신이 INPUT_FILE에서 각 라인, 내가 배운 좋은 작은 트릭으로 여러 명령을 실행할 수 있습니다 여기에 .


3
"좋은 작은 트릭"은 보안 관점에서 위험합니다.를 포함하는 인수가 $(somecommand)있으면 텍스트로 전달되지 않고 해당 명령이 실행됩니다. 마찬가지로, >/etc/passwd리디렉션 및 덮어 쓰기 /etc/passwd(적절한 권한으로 실행되는 경우) 등 으로 처리됩니다 .
Charles Duffy

2
대신 GNU 확장을 사용하는 시스템에서 다음을 수행하는 것이 훨씬 안전합니다.- xargs -d $'\n' sh -c 'for arg; do command1 "$arg"; command2 "arg"; command3 "arg"; done' _또한 입력 파일에서 한 줄에 하나의 쉘을 시작하는 대신 가능한 한 많은 인수를 각 쉘에 전달하기 때문에 더 효율적입니다.
Charles Duffy


0

@Wesley Rice의 답변 을 몇 번 편집 한 후 , 내 자신의 글을 쓰는 대신 자신의 답변을 계속 변경하기에 변경 사항이 너무 커지기 로 결정했습니다. 그래서 나는 내 자신을 작성하기로 결정했습니다!

파일의 각 줄을 읽고 다음과 같이 한 줄씩 실행하십시오.

#!/bin/bash
input="/path/to/txt/file"
while IFS= read -r line
do
  echo "$line"
done < "$input"

이것은 저자 Vivek Gite에서 직접 온 것입니다 : https://www.cyberciti.biz/faq/unix-howto-read-line-by-line-from-file/ . 그는 신용을 얻는다!

구문 : Bash Unix & Linux 쉘에서 한 줄씩 파일 읽기 :
1. bash, ksh, zsh 및 다른 모든 쉘이 한 줄씩 파일을 읽는 구문은 다음과 같습니다
. while read -r line; do COMMAND; done < input.file
3. -r옵션은 읽기 명령에 전달되었습니다. 백 슬래시 이스케이프가 해석되지 않도록합니다.
4. IFS=선행 / 후행 공백이 잘리지 않도록 읽기 명령 전에 옵션을 추가하십시오
.while IFS= read -r line; do COMMAND_on $line; done < input.file


그리고 지금 내가 가지고있는이 닫힌 질문에 대답하기 위해 : 파일에서 파일 목록을 'git add'할 수 있습니까? -내 대답은 다음과 같습니다.

참고 FILES_STAGED각 라인은 내가하고 싶은 파일에 대한 상대 경로 라인의 무리가 포함 된 파일의 절대 경로가 포함 된 변수 git add에 있습니다. 이 코드 스 니펫은 이 프로젝트 의 "eRCaGuy_dotfiles / useful_scripts / sync_git_repo_to_build_machine.sh" 파일의 일부가 되어 한 PC (예 : 코드가있는 컴퓨터)에서 다른 PC (예 : 코드가있는 컴퓨터)에서 개발중인 파일을 쉽게 동기화 할 수 있습니다. 더 강력한 컴퓨터) : https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles .

while IFS= read -r line
do
    echo "  git add \"$line\""
    git add "$line" 
done < "$FILES_STAGED"

참고 문헌 :

  1. https://www.cyberciti.biz/faq/unix-howto-read-line-by-line-from-file/ 에서 답변을 복사 한 곳
  2. 루프 구문 : https://www.cyberciti.biz/faq/bash-for-loop/

관련 :

  1. 파일의 내용을 한 줄씩 읽고 읽는 방법 git add: 파일에서 파일 목록을 'git add'할 수 있습니까?
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.