여러 줄 파일의 내용을 매개변수로 전달하는 방법은 무엇입니까?

여러 줄 파일의 내용을 매개변수로 전달하는 방법은 무엇입니까?

매개변수를 사용하여 스크립트를 실행하려고 합니다 -t. 이 매개변수는 텍스트를 나타내며 이론적으로 여러 줄의 값이 허용됩니다. 명령줄에서는 여기에 있는 문서가 작동할 것이라고 가정하지만 명령줄에 긴 내용을 입력하는 것을 좋아하지 않습니다. 그리고 이 파일을 잘 보관해서 나중에 다시 전달할 수 있기를 바라겠습니다.

어떻게 해야 할지 모르겠습니다. 그렇게 하면 cat foo | xargs echo한 줄로 인쇄됩니다. 이렇게 하면 문제가 해결됩니다. cat foo | xargs -d='' echo하지만 내용에 따라 문서의 공백이나 일반 구조가 변경되는 이해할 수 없는 일이 일어나고 있다고 생각하게 됩니다.

특수 문자나 형식 변경에 대해 걱정할 필요 없이 여러 줄 파일을 매개변수로 전달할 수 있는 방법은 무엇입니까?

답변1

  1. 그냥 파일 이름을 전달하면 안 되나요? 스크립트가 파일 이름을 처리하는 방법을 아직 모르는 경우 수정하십시오(예: 알 수 없는 모든 인수를 파일 이름으로 처리 및/또는 -f입력 파일 이름 옵션 추가). 파일명이 존재하지 않거나 권한 등으로 인해 읽을 수 없는 경우에는 오류 검사 코드를 추가하고 적절하게 대응해야 합니다.

  2. 당신의 주장을 인용하세요. 예를 들어-t "$(cat foo)"

답변2

xargs -d=''( -dGNU 구현의 확장)은 쉘 언어의 인용 구문과 동일합니다 xargs. 이는 구분 기호로 사용하라는 의미입니다.xargs -d=''xargs=

예를 들어 는 및 매개변수 로 호출 echo foo=bar | xargs -d= cmd됩니다 .cmdfoobar<newline>

xargs -d ''or ( 현재 버전에서는 or로 시작하는 다른 긴 옵션이 없기 때문에 로 xargs --delimiter=축약할 수 있음) 을 사용 하면 구문 오류가 발생합니다.xargs --del=xargs --d=xargsd

NUL 문자를 구분 기호로 사용하는 xargs -d '\0'(아직 표준은 아니지만) 이식성이 뛰어난 와 동일한 를 사용할 수 있습니다 . NUL 문자는 텍스트 파일에 표시되어서는 안 되며, 인수가 NUL로 구분된 문자열로 xargs -0시스템 호출에 전달되기 때문에 기본 제공 명령이 아닌 인수로 전달할 수 없습니다 .execve()

그래서:

xargs -I'<TEXT>' -0a file cmd -t '<TEXT>' other args

( -a다른 GNU 확장으로) xargsas 인수의 정확한 내용이 ²에 전달됩니다.filecmd -t

그러나 만약 file그것이foobar 철사예를 들어 이렇게 하면 줄 구분 기호( )를 포함하여 전체 줄이 전달됩니다 "foobar\n".

또는 POSIX와 유사한 셸에서 다음을 수행할 수 있습니다.

cmd -t "$(cat file)" other args

명령 대체는 내부 명령의 출력에서 ​​모든 후행 줄 바꿈을 제거하므로 바람직할 수 있습니다. 예를 들어 출력에 NUL 문자가 포함되어 있으면 일부 쉘 에서는 bash해당 문자를 제거합니다( "$(tr -d '\0' < file)"이 동작을 얻으려면 어떤 쉘에서도 사용하지 말고 사용하세요).

주위의 큰따옴표가 중요합니다. 그것들이 없으면 확장이 어려워질 것입니다나뉘다+전반적인 상황(나뉘다파일에 $IFS( 및새로운 팀$IFS) 또는 와일드카드의 기본값 입니다 .

"$(<file)"ksh, zsh 또는 bash에서는 파일 자체를 읽는 대신 "$(cat file)"실행을 최적화하는 데 사용할 수도 있습니다 cat(bash에서는 여전히 하위 프로세스에서 수행됩니다).

에서는 모듈 에서 특수 연관 배열을 사용할 zsh수도 있습니다 .$mapfilezsh/mapfile

zmodload zsh/mapfile
cmd -t "$mapfile[path/to/file]" other args

execve()즉, NUL( 첫 번째 NUL 이후 arg가 잘림) 및 후행 개행 문자를 포함하여 콘텐츠가 있는 그대로 전달됩니다 .

rc셸 또는 파생물 에서는 다음을 수행할 수 있습니다.

cmd -t ``(){cat file} other args

여기서는 사용할 수 없는 구분 기호를 지정할 수 있는 ``(sep)cmd명령 대체의 변형(거기)입니다 . `cmd이 셸에서는 후행 줄 바꿈이 제거되지 않으므로 전체 파일 내용이 그대로 전달됩니다.

어쨌든, 대부분의 시스템에서는 명령 인수 3의 전체 크기에 제한이 있습니다(최신 버전의 Linux에서는 다음으로 변경할 수 있음).스택 크기제한) 및 Linux의 단일 매개변수 크기(최대 128KiB)입니다.


이제 특수 문자에 대한 걱정 없이 여러 줄 문자열을 문자 그대로 전달하려면 다음을 수행할 수 있습니다.

cmd -t 'the multiline here
where the only character you have to
worry about in Bourne-like shells is 
single quote which you have to enter
as '\'', that is leave the quotes, enter
it with other quoting operators (here \)
and resume the quotes'

rc작은따옴표는 셸 에서 작은따옴표 안에 입력할 수 있거나 (이 경우 '...'유일한 형식의 따옴표임) 이 옵션이 활성화된 경우 예를 들면 다음과 같습니다. zsh바라보다rcquotes''cmd -t 'It''s simpler like that'Unix 쉘에서 일반 문자와 같은 특수 문자를 사용하는 방법은 무엇입니까?다양한 쉘에서의 인용에 대한 세부사항.

또는 여기 문서를 사용하여 변수에 저장할 수 있습니다.

multi=$(cat << 'EOF')
multiline string here, only worry would be about
an EOF line by itself though also note that
all trailing newlines, so that includes all
trailing empty lines are removed, including these:


EOF
)
cmd -t "$multi" # note the quotes again

또는 다음과 같이 직접적으로:

cmd -t "$(cat << 'EOF'
multi
line
here
EOF
)"

따옴표를 주의하세요 EOF. 이것이 없으면 매개변수 확장(예: $var), 명령 대체(예: $(cmd)또는 `cmd`) 및 산술 확장( $((...)))이 계속 수행됩니다.

mksh셸 에서는 다음을 사용할 수 있습니다.

cmd -t "$(<< 'EOF'
multi
line
EOF
)"

where cat및 fork는 본질적으로 여러 줄 인용 형식이 되도록 최적화되어 있습니다.


¹ 내장 명령이나 함수에 대한 인수로 전달될 수 없으며 심지어 대부분의 셸의 변수에 저장될 수도 없습니다. zsh이는 제가 아는 유일한 예외입니다.

² 파일이 비어 있지 않은 한. 파일이 비어 있으면 -I명령이 전혀 실행되지 않으며 널 인수로 명령을 호출하려면 파일에 NUL 문자가 포함되어야 합니다.

³ 기술적으로 제한( execve()다시 시스템 호출에서이므로 쉘 내장/함수에는 적용되지 않음)은 인수의 누적 크기입니다.그리고 환경그리고 각 매개변수의 크기와 envvar 문자열 포인터도 고려되는 경우가 많기 때문에 특정 매개변수 세트가 제한을 위반할지 여부를 미리 예측하기 어려운 경우가 많습니다.

관련 정보