我有一个相对较小的文件名列表,这些文件名是从基于find
.文件名包含空格和可能的标点符号,但绝对不包含其他非打印字符或换行符。
例如,
Netherlands/Purge (GDPR) 2020-01-09.txt
Netherlands/Purge (GDPR) 2020-01-27.txt
Switzerland/New mailing 2020-01-27.txt
我想将这些文件作为一组(vi file1 file2 file3
而不是vi file1; vi file2; vi file3
)进行编辑,部分原因是我可以轻松地在它们之间前后跳转。
我已经开始了使用生成的文件名列表作为参数列表 - 带空格
,有一个标准find -print0 | xargs -0 mycommand
解。不幸的是,当mycommand
编辑者是编辑者时,这不起作用,因为尽管xargs
可以组装要编辑的文件集,标准输入已从管道中占用,我看不到就地运行编辑器的方法。我无法使用,find -exec vi {} +
因为我正在使用管道来验证文件名集,而不仅仅是find
其本身。
我的另一个选择是复制和粘贴,组合文件名列表,用引号括起来,然后在结果前面加上vi
.对于这三个文件来说,这很简单,但在一般情况下,它不是一个易于重用的解决方案,
vi 'Netherlands/Purge (GDPR) 2020-01-09.txt' 'Netherlands/Purge (GDPR) 2020-01-27.txt' 'Switzerland/New mailing 2020-01-27.txt'
给定一个 GNU/Linux 平台作为bash
我的首选 shell(如果它很重要),我如何编辑类似生成的文件列表?
答案1
既然你在 Bash,
#!/bin/bash
readarray -d '' -t files < <(find path -type f -print0)
vi -- "${files[@]}"
替换find path -type f -print0
为您的实际管道。
尽管您的文件没有换行符,但用户已添加对此类文件名的支持格伦·杰克曼。
要使用制表符而不是缓冲区vi
,请添加-p
标志:vi -p ...
。
如果不需要管道,您可以直接使用该-exec
选项:
find path -type f -exec vi -- {} +
答案2
不幸的是,当 mycommand 是编辑器时,这不起作用,因为尽管 xargs 可以组装要编辑的文件集,但 stdin 已经从管道中占用,并且我看不到就地运行编辑器的方法。
这种方式记录在 GNU Findutils 的手册页中xargs
:
-o, --open-tty
Reopen stdin as /dev/tty in the child process before executing
the command. This is useful if you want xargs to run an inter‐
active application.
这样你就可以使用
find . -name 'pattern' -print0 | xargs -0o vim
然而,这是一个较新的功能。我在具有 xargs 4.4.2 的旧系统中看不到它;我在 Ubuntu 18 上看到它,它有 xargs 4.7.0。
现在xargs
可能没有-o
十年前的选项,但 Bash 进程替代十年前就存在,并且xargs
可以-a
选择从文件读取而不是标准输入。
所以这个问题是可以解决的,不需要xargs -o
这样:
xargs -0 -a <(find . -name 'pattern' -print0) vim
因为xargs
正在读取(它认为是)作为参数接收的文件,所以它保留了标准输入。
答案3
从评论中我得到类似的东西,这是你的命令:
find -type f -mtime +14 -mtime -22 -iname '*.xml' | while IFS= read -f x; do xmlstarlet sel -T -t -v '//magicElement' -n "$x" | grep -q magicValue && echo "$x"; done
while
您可以使用管道-exec sh -c '...'
来过滤文件,而不是通过管道连接到- 循环:
find -type f -mtime +14 -mtime -22 -iname '*.xml' \
-exec sh -c 'xmlstarlet sel -T -t -v "//magicElement" "$1" | grep -q magicValue' find-sh {} \; \
-exec vi -- {} +
尝试:
考虑三个文件:
.
├── a:<magicElement>magicValue</magicElement>
├── b:<magicElement>magicValue</magicElement>
└── c:<magicElement>someOtherValue</magicElement>
$ find . -type f \
-exec sh -c 'xmlstarlet sel -T -t -v "//magicElement" "$1" | grep -q magicValue' find-sh {} \; \
-exec echo vi -- {} +
输出:
vi -- ./a ./b
答案4
这是我多年来针对这个问题使用的两个丑陋的技巧。两者都需要 X。
find ... -print0| ...| xargs -0r gvim -f
find ... -print0| ...| xargs -0r xterm -e vim
即使通过 ssh,它也能工作。