IT/Unix&Linux

xargs 로 넘기니 스페이스(space.. 빈 공백하나) 에 대해 split 이 일어나더라?

iezs 2019. 3. 19. 12:30


https://ezsnote.tistory.com/entry/cat-으로-읽은-여러줄-멀티라인-xargs-로-각각-넘기기


를 통해서 output 리스트를 한줄한줄씩 읽어서 function 대입 (...뭔가의 처리)를 하게 해놓은뒤 평화로운 나날을 보내는중... 갑자기 이상한 현상이 나왔다.


갑자기 파싱된 element 값을 function 대입하고 있던것이다. ... 앵? 난 줄을 읽어와서 그걸 function 처리하려고 했던건데? 


확인해보니.. 새롭게 값이 추가되면서 그 값중에 공백이 들어가는 부분이 있었는데 xargs 가 그 공백을 새로운 줄로 처리하고 있었다; 


즉 

1_2_3_4 를 한줄로 읽어서 넘기고 있었는데 (  '_' 는 구분자.. delim) 


1_2_3_4_5 1  .. 처럼 뒤에 '5 1' 이 추가되면서


1_2_3_4_5 까지만 읽고 1을 다음 데이타.. 즉 다음줄로 처리하려고 했던것이다. 


찾아보면 다양항 스킬을 난무해가며 이걸 처리하는 방법들이 있다. xargs 의 옵션질 및 뭐... print 로 명령줄을 만들어서 그걸 실행하게 할 수도 있고 등등등...


근데... 이 간단한 처리.. 를 위한 간단한 해결방법을 쓰기로 했다. sed 를 써서 공백을 "" empty 로 치환하는거지. 



$> 원하는 필터링중... | sed 's/ //g' | xargs 원하는 function 


sed 로 준  s 와 g 에 대해서 예전에 스크립트좀 공부했다면 무슨의미인지 알것이다. 즉 시작과 끝까지.. 이다.해서


'처음/공백을/empty로/끝까지'  라고 생각하면된다.


해서 넘겨받은 한 줄에 대해서 빈 스페이스를 모두 "" empty 형태로 바꾸고 output 으로 내놓게 된다. 이걸 다시 뭔가를 처리할 function (이게 뭐.. 스크립트가 될 수도 있고 파이썬이 될수도 있고 등등 ) 에게 넘겨주는 것이다. 


!!!!


https://stackoverflow.com/questions/23142776/xargs-split-at-newlines-not-spaces


xargs 에서도 간단히 할 수 있다. -d 주면 모두 넘긴다. 다만 -d 는 GNU 확장에서나 먹히는 명령이므로 -0(숫자) 으로 하면 된다.




14

here is my problem in short

$ echo 'for i in $@; do echo arg: $i; done; echo DONE' > /tmp/test.sh
$ echo "ac\nbc\ncc\n" | xargs bash /tmp/test.sh 
arg: ac
arg: bc
arg: cc
DONE

Which is what i expect, but

$ echo "ac s\nbc s\ncc s\n" | xargs -d \n bash /tmp/test.sh
arg: ac
arg: s
arg: bc
arg: s
arg: cc
arg: s
DONE

Shouldn't the output be?

arg: ac s
arg: bc s
arg: cc s
DONE

How do I get the 2nd output with xargs?

16

Try:

printf %b 'ac s\nbc s\ncc s\n' | xargs -d '\n' bash /tmp/test.sh

You neglected to quote the \n passed to -d, which means that just n rather than \n was passed to xargs as the delimiter - the shell "ate" the \ (when the shell parses an unquoted string, \ functions as an escape character; if an ordinary character follows the \ - n in this case - only that ordinary character is used).

Also heed @glenn jackman's advice to double-quote the $@ inside the script (or omit the in "$@"part altogether).

Also: xargs -d is a GNU extension, which, for instance, won't work on FreeBSD/macOS. To make it work there, see @glenn jackman's xargs -0-based solution.


Note that I'm using printf rather than echo to ensure that the \n instances in the string are interpreted as newlines in all Bourne-like shells:
In bash and ksh[1]echo defaults to NOT interpreting \-based escape sequences (you have to use -e to achieve that) - unlike in zsh and strictly POSIX-compliant shells such as dash.
Therefore, printf is the more portable choice.

[1] According to the manual, ksh's echo builtin exhibits the same behavior as the host platform's external echo utility; while this may vary across platforms, the Linux and BSD/macOS implementations do not interpret \ escape sequences by default.

5

Your shell script needs to use "$@" not $@

See http://www.gnu.org/software/bash/manual/bashref.html#Special-Parameters


I see in the xargs manual on my machine:

xargs reads items from the standard input, delimited by  blanks [...] or newlines

(emphasis mine)

Thus:

$ echo $'ac s\nbc s\ncc s\n' | xargs bash /tmp/test.sh  
arg: ac
arg: s
arg: bc
arg: s
arg: cc
arg: s
DONE

$ printf "%s\0" "ac s" "bc s" "cc s" | xargs -0 bash /tmp/test.sh
arg: ac s
arg: bc s
arg: cc s
DONE

With the former, you get the equivalent of

bash /tmp/test.sh ac s bc s cc s

versus using null-separator

bash /tmp/test.sh "ac s" "bc s" "cc s"

You need to be clear about what the delimiter is with xargs when the data contains whitespace. 

$ printf "%s\n" "ac s" "bc s" "cc s" | xargs -d $'\n' bash /tmp/test.sh
arg: ac s
arg: bc s
arg: cc s
DONE

$ echo $'ac s\nbc s\ncc s\n' | xargs -d $'\n' bash /tmp/test.sh  
arg: ac s
arg: bc s
arg: cc s
arg:  
DONE

Note the extra arg in the last case, echo already adds a newline, so you don't need an extra one unless you use echo -n

  • 1
    Good advice, though the real problem lies with not quoting the \n passed to -d. – mklement0 Apr 17 '14 at 20:47
  • That is a separate issue, but thanks for pointing it out. – glenn jackman Apr 17 '14 at 20:48
  • 1
    You're absolutely right: both issues need to be addressed to fix the problem (and they each in isolation or combination produce the symptom). Your printf-\0-xargs -0 solution is a nice alternative, because it is more portable (will work on OSX too, for instance, where xargs -d is not available). – mklement0 Apr 17 '14 at 21:01