在 PowerShell 中,我可以在一行中运行如下命令
Get-ChildItem | foreach {
if ($_ -match '.+?\.py$' -eq $true) {
$_ | Do-Thing -WithFile
}
if ($_ -match '.+?\.pdf$' -eq $true) {
$_ | Do-Thing -WithOtherFile
}
}
就像这样
Get-ChildItem | foreach { if ($_ -match '.+?\.py$' -eq $true) { $_ | Do-Thing -WithFile } if ($_ -match '.+?\.pdf$' -eq $true) { $_ | Do-Thing -WithOtherFile } }
我欣赏的这个具体功能是能够通过引用管道对象以便$_
在下一个命令中使用,并且能够通过基于输出的分割片段进行条件执行| foreach {}
。
我知道在 bash 中,通过以下方式可以很容易地同时 grep 多个模式
> ls | egrep '\.py$|\.pdf$'
some_foo.py
some_bar.py
foo.pdf
bar.pdf
是否可以使用默认情况下可用的方法在一行中扩展此方法,以便我可以执行相当于
| foreach { if ($_ -match '.+?\.py$') {Do-Thing -With $_ } if (...) { Do-Thing -WithOther $_ } }
或者 Bash 是否仅将一个命令的标准输出重定向到另一个命令的标准输入?我发现 PowerShell 中有很多这种动态的杂项用途,但没有听说过 Bash 中有等效用途。
这不是什么阻塞,用通常的语法编写脚本就可以了,我只是好奇,因为它在 PS 中非常有用。
寻找:$_ , | foreach {}
等价物,我可以在其中拆分输出、检查其条件,然后能够通过某个名称引用拆分的输出部分。在 PSs 的情况下,$_
我确实知道 PS 在很多方面与 Bash 有着根本的不同,所以如果这是 PS 独有的,我不会感到惊讶。
为了更好地理解上下文,下面是 PS 中的一个例子,你可以递归搜索带有 python 和 pdf 扩展名的文件,并在各自的文本文件中记录它们
Get-ChildItem -Recurse | foreach {
if ($_ -match '.+?\.py$' -eq $true) {
$_ | Out-File -encoding utf8 -Append py_list.txt
}
if ($_ -match '.+?\.pdf$' -eq $true) {
$_ | Out-File -encoding utf8 -Append pdf_list.txt
}
}
答案1
是(几乎)也不是。Bash 首先不支持流水线“对象”——它的管道,即使是内部管道,仍然建立在子进程和普通的 stdio(字节流)上,因此你只能与普通的文本(例如,逐行列出文件路径),而不是复杂的对象。
因此最接近的等价物是while read -r <var>; do ...; done
。稍后会详细介绍。
你的具体的任务可以最好的使用简单的for <var> in <words>
循环处理通配符:
for file in *; do
if [[ $file == *.py ]]; then
do_something_with "$file"
elif [[ $file == *.pdf ]]; then
do_something_else --with "$file"
fi
done
您甚至不需要重现明确的检查——您可以改为使用两个循环:
for file in *.py; do
do_something_with "$file"
done
for file in *.pdf; do
do_something_else --with "$file"
done
做同样的事情递归地,你可以 a) 使用 Bash 的递归通配符:
shopt -s globstar
for file in **/*; do
if ...; then ...; fi
done
或者 b) 使用find
并循环标准输入中的每一行:
find . -type f | while read -r file; do
if [[ $file == *.py ]]; then
...
fi
done
(是的,我应该习惯IFS="" read -r <var>
处理以空格结尾的文件名 - 但幸运的是我的系统上没有这样的文件名,所以我不会打扰。)
再次,您可以跳过手动文件名检查并预先请求您需要的内容。
shopt -s globstar
for file in **/*.pdf; do
do_something_with "$file"
done
变体b:
find . -type f -name "*.pdf" | while read -r file; do
do_something_with "$file"
done
相同,但利用寻找的 -exec 选项:
find . -type f -name "*.pdf" -exec do_something_with {} \;