执行递归查找并用 sed 替换仅更改第一个文件
Performing a recursive find and replace with sed only changes first file
我正在尝试递归搜索当前目录,对找到的每个 .txt
文件的第一行执行 sed 替换。
运行 这两个命令中的任何一个,在 MacOS 上:
find . -name "*.txt" -exec sed -i '' '1 s/([^()]*)//g' {} +
find . -name '*.txt' -print0 | xargs -0 sed -i '' '1 s/([^()]*)//g'
导致相同的结果。仅找到的 "first" 文件对其执行了 sed
操作。这似乎是因为 sed -i '' '1 s/([^()]*)//g'
中的 1
。奇怪的是,即使这导致只使用第一个文件,它也仍然只在该文件的第一行执行 sed 替换;它应该。
如果我把命令改成这个
find . -name '*.txt' -print0 | xargs -0 sed -i '' '2 s/([^()]*)//g'
仍然只是第一个文件被更改,但现在第二行有替换。那么我的问题是,为什么这似乎只影响
返回的第一个文件
find . -name '*.txt' -print0
编辑澄清
我应该通过逐步重现问题来阐明我的意思,只有 "first" 文件对其执行了 sed 操作。首先,
这是文件夹层次结构(注意 "folder 1" 中的 space):
.
├── folder\ 1
│ └── test1.txt
├── folder2
│ └── test2.txt
├── folder3
│ └── test3.txt
└── folder4
└── test4.txt
每个 .txt
文件只包含这一行:
This should stay (this should go)
当运行上述任一命令时,更改的是文件test2.txt
,问题是它是唯一更改的文件!
现在,文件包含以下内容:
test1.txt: This should stay (this should go)
test2.txt: This should stay
test3.txt: This should stay (this should go)
test4.txt: This should stay (this should go)
我相信这是因为命令的第一部分,例如
find . -name '*.txt' -print0
给出以下内容(每个由 [=28=]
空字符分隔)
./folder2/test2.txt./folder3/test3.txt./folder4/test4.txt./folder 1/test1.txt
通过随机更改文件夹和文件名,很明显,更改的始终是上述 [=28=]
分隔列表中的第一个文件。
所以问题仍然存在,调用 sed 阻止它在所有文件上被调用的原因是什么?
谢谢!
我想关于第一个命令的问题已由 Beta 回答,让我回答第二个。
尝试将 -t
(测试)选项设置为 xargs
,看看命令行如何
已展开:
find . -name '*.txt' -print0 | xargs -0 -t sed -i '' '1 s/([^()]*)//g'
它将输出如下内容:
sed -i '' 1 s/([^()]*)//g ./test1.txt ./test2.txt ./test3.txt ./test4.txt
xargs
的默认行为是执行指定的命令
(sed
在这种情况下)一次从标准中读取所有参数
输入。
此外 sed
不会重置跨多个输入文件和 s
命令的行号
以上仅适用于第一个文件。
您可以使用 -l1
选项更改 xargs
的行为:
find . -name '*.txt' -print0 | xargs -0 -l1 -t sed '1 s/([^()]*)//g'
输出:
sed -i '' 1 s/([^()]*)//g ./test1.txt
sed -i '' 1 s/([^()]*)//g ./test2.txt
sed -i '' 1 s/([^()]*)//g ./test3.txt
sed -i '' 1 s/([^()]*)//g ./test4.txt
然后 sed
将按预期工作。
我正在尝试递归搜索当前目录,对找到的每个 .txt
文件的第一行执行 sed 替换。
运行 这两个命令中的任何一个,在 MacOS 上:
find . -name "*.txt" -exec sed -i '' '1 s/([^()]*)//g' {} +
find . -name '*.txt' -print0 | xargs -0 sed -i '' '1 s/([^()]*)//g'
导致相同的结果。仅找到的 "first" 文件对其执行了 sed
操作。这似乎是因为 sed -i '' '1 s/([^()]*)//g'
中的 1
。奇怪的是,即使这导致只使用第一个文件,它也仍然只在该文件的第一行执行 sed 替换;它应该。
如果我把命令改成这个
find . -name '*.txt' -print0 | xargs -0 sed -i '' '2 s/([^()]*)//g'
仍然只是第一个文件被更改,但现在第二行有替换。那么我的问题是,为什么这似乎只影响
返回的第一个文件find . -name '*.txt' -print0
编辑澄清
我应该通过逐步重现问题来阐明我的意思,只有 "first" 文件对其执行了 sed 操作。首先,
这是文件夹层次结构(注意 "folder 1" 中的 space):
.
├── folder\ 1
│ └── test1.txt
├── folder2
│ └── test2.txt
├── folder3
│ └── test3.txt
└── folder4
└── test4.txt
每个 .txt
文件只包含这一行:
This should stay (this should go)
当运行上述任一命令时,更改的是文件test2.txt
,问题是它是唯一更改的文件!
现在,文件包含以下内容:
test1.txt: This should stay (this should go)
test2.txt: This should stay
test3.txt: This should stay (this should go)
test4.txt: This should stay (this should go)
我相信这是因为命令的第一部分,例如
find . -name '*.txt' -print0
给出以下内容(每个由 [=28=]
空字符分隔)
./folder2/test2.txt./folder3/test3.txt./folder4/test4.txt./folder 1/test1.txt
通过随机更改文件夹和文件名,很明显,更改的始终是上述 [=28=]
分隔列表中的第一个文件。
所以问题仍然存在,调用 sed 阻止它在所有文件上被调用的原因是什么?
谢谢!
我想关于第一个命令的问题已由 Beta 回答,让我回答第二个。
尝试将 -t
(测试)选项设置为 xargs
,看看命令行如何
已展开:
find . -name '*.txt' -print0 | xargs -0 -t sed -i '' '1 s/([^()]*)//g'
它将输出如下内容:
sed -i '' 1 s/([^()]*)//g ./test1.txt ./test2.txt ./test3.txt ./test4.txt
xargs
的默认行为是执行指定的命令
(sed
在这种情况下)一次从标准中读取所有参数
输入。
此外 sed
不会重置跨多个输入文件和 s
命令的行号
以上仅适用于第一个文件。
您可以使用 -l1
选项更改 xargs
的行为:
find . -name '*.txt' -print0 | xargs -0 -l1 -t sed '1 s/([^()]*)//g'
输出:
sed -i '' 1 s/([^()]*)//g ./test1.txt
sed -i '' 1 s/([^()]*)//g ./test2.txt
sed -i '' 1 s/([^()]*)//g ./test3.txt
sed -i '' 1 s/([^()]*)//g ./test4.txt
然后 sed
将按预期工作。