Can xargs' default delimiter be changed?

坚强是说给别人听的谎言 提交于 2019-12-05 03:56:55

I tested xargs -d '\n' -n1 echo on the command line and it worked as advertised; breaking the input up into single lines and echoing it.

You could be being bitten by assumptions regarding shell escaping during variable assignment. For instance, if your shell script is similar to this:

CMD="xargs -d '\n' -n1 echo"
cat inputfile | $CMD

then an error occurs, because the double-quotes around the entire CMD string preserve both the single-quotes and the backslash in the delimiter.

If you are enclosing the xargs command within quotes, you could change it to the following (no single-quotes)

CMD="xargs -d \n -n1 echo"
cat inputfile | $CMD

and it will likely function as you need.

Tested on CentOS 6.4, xargs version 4.4.2

If your version of xargs doesn't support setting a different delimiter (like the one on a 2011 FreeBSD server...), you can use tr to turn your delimiters into something xargs will work with. You might need to use a few translations before and after if your input has characters that your xargs considers delimiters (such as spaces) or you could simply translate your delimiters to NULL/0x0 and pass the -0 argument to xargs.

Here is an example of using xargs to find any file in $PATH that could be a possible shell to use (the reason I'm here, then I came up with another answer):
echo $PATH | tr ':' '\0' | xargs -0 ls | grep sh | sort

I have ~/bin in my PATH and keep a short script with my favorite defaults accessible by all shells on my system (at different times I use Dash, Bash, and Fish). It's tiny:

!/usr/bin/env sh
exec xargs -rd\\n "$@"

The script is called x to avoid conflicts with scripts expecting the standard xargs defaults. If you try to replace xargs itself, which I don't recommend, make sure your ~/bin appears higher in your PATH than the system xargs. which -a xargs tells me that the only xargs exists at /usr/bin/xargs in my system so I know my home directory, /home/stephen/bin, must appear before it like so:

$ echo "$PATH"
/home/stephen/bin:...:/usr/bin:...

Either way, as a script accessible by all programs, this means you can do things like find|x grep and sh -c 'x ...'.

If you use Bash and prefer an alias, you can also just use:

alias x=xargs -rd\\n\ # \n delim, don't run on empty in, + alias expansion

Note the trailing space for alias expansion. This lets you chain aliases. For example, if in addition to the above alias I had an alias for grep called g, the following would work:

# extended regex, skip binaries, devices, sockets, & dirs, colored, & line
# -buffered. use a non-canonical alias instead of GREP_OPTIONS which may wreck
# assuming scripts
alias g='grep -EID skip -d skip --color=auto --line-buffered'

$ find|x g foo

The x / xargs script approach can't do this effectively by itself.

Since I switch between shells and use one PC mostly, I keep the handful of aliases I need as separate scripts in ~/bin and shell agnostic aliases in a helper script, ~/.sh_aliases, which is sourced by ~/.shrc, ~/.bashrc, and ~/.config/fish/config.fish as they all support a Bash-like alias syntax. If I worked on multiple PCs regularly, I would probably try to consolidate these into ~/.bashrc instead.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!