xargs 不适用于 SUSE

xargs doesn't work on SUSE

This problem occurs only on , it works on ubuntu and even on windows through

我的意思是用另一个词替换几个文件中的一个词。

这就是我正在尝试的:

$  grep -Inrs MY_PATTERN src/ | cut -d: -f1 | xargs sed -i 's/MY_PATTERN/NEW_WORD/g'

sed: can't read path/to/a/found/file_1: No such file or directory
sed: can't read path/to/a/found/file_2: No such file or directory
sed: can't read path/to/a/found/file_3: No such file or directory
...

知道

$  grep -Inrs MY_PATTERN src/ | cut -d: -f1
path/to/a/found/file_1
path/to/a/found/file_2
path/to/a/found/file_3

更新1

这也不行

$  grep -lZ -Irs MY_PATTERN src/ | xargs -0 ls

ls: cannot access path/to/a/found/file_1: No such file or directory
ls: cannot access path/to/a/found/file_2: No such file or directory
ls: cannot access path/to/a/found/file_3: No such file or directory
...

$ ls -al path/to/a/found/file_1 | cat -vet
-rw-r--r-- 1 webme 886 Feb  1 13:36 path/to/a/found/file_1$

更新2

$ whoami
 webme

$ uname -a
 Linux server_vm_id_34 3.0.101-68-default #1 SMP Tue Dec 1 16:21:37 UTC 2015 (ed01a9f) x86_64 x86_64 x86_64 GNU/Linux

更新3

$ grep --version
grep (GNU grep) 2.7
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Mike Haertel and others, see <http://git.sv.gnu.org/cgit/grep.git/tree/AUTHORS>.


$ xargs --version
xargs (GNU findutils) 4.4.0
Copyright (C) 2007 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Eric B. Decker, James Youngman, and Kevin Dalley.
Built using GNU gnulib version e5573b1bad88bfabcda181b9e0125fb0c52b7d3b

# My project path /home/users/webme/projects/my_project
$ df -T
 dl360d-01:/homeweb/users/webme nfs   492625920 461336576  31289344  94% /home/users/webme

$ id
 uid=1689(webme) gid=325(web) groups=325(web)

$ mount -v
/dev/vda2 on / type btrfs (rw)
proc on /proc type proc (rw)
sysfs on /sys type sysfs (rw)
debugfs on /sys/kernel/debug type debugfs (rw)
udev on /dev type tmpfs (rw,mode=0755)
tmpfs on /dev/shm type tmpfs (rw,mode=1777)
devpts on /dev/pts type devpts (rw,mode=0620,gid=5)
/dev/vda1 on /boot type ext3 (rw,acl,user_xattr)
/dev/vdb on /appwebinet type xfs (rw)
rpc_pipefs on /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw)
dl360d-01:/homeweb/users on /homeweb/users type nfs (rw,soft,bg,addr=xx.xx.xx.xx)
dl360d-01:/appwebinet/tools/list on /appwebinetdev/tools/list type nfs (ro,soft,sloppy,addr=xx.xxx.xx.xx)
dl360d-01:/homeweb/users/webme on /home/users/webme type nfs (rw,soft,bg,addr=xx.xxx.xx.xx)
none on /proc/sys/fs/binfmt_misc type binfmt_misc (rw)
none on /var/lib/ntp/proc type proc (ro,nosuid,nodev)

我没有exportfs,我在sudo zypper install exportfs

中也没有

是这种情况下最简单、最可靠的解决方案。
这个 答案可能仍然对 (a) -d-n 选项的讨论以及 (b) 如何 preview xargs 将执行的命令。

据我了解,SUSE 使用 GNU 实用程序,因此您可以 使用 xargs -d'\n':

grep -Inrs MY_PATTERN src/ | cut -d: -f1 | xargs -d'\n' sed -i 's/MY_PATTERN/NEW_WORD/g'

xargs -d'\n' 确保 每个输入行 作为一个整体 被视为它自己的参数(保留带空格的文件名的完整性),同时仍然传递尽可能多的参数(通常,全部一次

(相比之下,-n 1 会用空格分隔参数,并一次用 1 个参数调用目标命令。)

如果你想预览执行的命令,使用辅助. bash 命令:

grep -Inrs MY_PATTERN src/ | cut -d: -f1 |
  xargs -d'\n' bash -c 'printf "%q " "$@"' _ sed -i 's/MY_PATTERN/NEW_WORD/g'

继续阅读以获得解释。


可选的背景信息。

xargs 有自己的选项,-p,用于预览要执行的命令 提示确认,但预览 没有反映参数边界 的方式直接从 [=113= 调用命令时必须指示它们].

一个简单的例子:

$ echo 'hi, there' | xargs -p -d '\n' printf '%s'
printf %s hi, there ?...

xargs实际上执行的是printf '%s' 'hi, there'等价,但那是没有反映在-p的提示中。

解决方法:

$ echo 'hi, there' | xargs -d '\n' bash -c 'printf "%q " "$@"' _ printf '%s'
printf %s hi\,\ there

通用辅助 bash 命令 - bash -c 'printf "%q " "$@"' _,插入到目标命令之前 - 引用 xargs 传递的参数 - on需求,仅在必要时 - 以 shell 需要的方式将每个识别为 单个参数 ,并加入他们有空格。

最终结果是 a shell command 被打印出来,即 equivalent what xargs 将执行 (尽管如您所见,不能保证保留输入的引用样式)。

我建议保持简单:

$ grep -lZ -Irs foo * | xargs -0 sed -i 's/foo/bar/g'

grep -l 只输出匹配的文件名,这正是您在此管道中想要的。 grep -ZNUL 终止每个匹配的文件名,xargs -0 可以选择。这允许嵌入 white-space 的文件名在 grep 和 xargs 之间不受限制地传递。


# show the structure
$ tree
.
└── path
    └── to
        └── a
            └── found
                ├── file_1
                ├── file_2
                └── file_3

# show the contents
$ grep . path/to/a/found/file_*
path/to/a/found/file_1:a foo bar
path/to/a/found/file_2:a foo bar
path/to/a/found/file_3:a foo bar

# try it out
$ grep -lZ -Irs foo * | xargs -0 ls -l
-rw-rw-r-- 1 bishop bishop 10 Feb 13 09:13 path/to/a/found/file_1
-rw-rw-r-- 1 bishop bishop 10 Feb 13 09:13 path/to/a/found/file_2
-rw-rw-r-- 1 bishop bishop 10 Feb 13 09:13 path/to/a/found/file_3