试图将 for /f "tokens=*" %%a in ... 转换为 SHELL
Posted
技术标签:
【中文标题】试图将 for /f "tokens=*" %%a in ... 转换为 SHELL【英文标题】:Trying to convert for /f "tokens=*" %%a in ... to SHELL 【发布时间】:2021-02-19 06:59:16 【问题描述】:我正在尝试借助这种converter manual 将whole BATCH 脚本转换为SHELL 脚本。
我几乎完成了,但我正在努力转换这个 FOR LOOP:
for /f "tokens=*" %%a in ('%adb% shell mkdir /usr/ui/^|find /i "File exists"') do (
if not errorlevel 1 goto :cannot_patch
)
我知道for /f
是
循环命令:针对一组文件 - 有条件地针对每个项目执行一个命令。
但是,由于我是 SHELL SCRIPT(以及 BASH)的菜鸟,我最好的尝试是:
for -f "tokens=*" a in ( '$ADB shell mkdir /usr/ui/^|find /i "File exists"' ); do
if [ $? -nq 1 ]
then
cannot_patch
fi
done
这不起作用,导致Syntax error: Bad for loop variable
。
非常感谢任何提示、链接或建议。
编辑
我试图了解 ('%adb% shell mkdir /usr/ui/^|find /i "File exists"')
到底在做什么。
我以为那些是 sh 命令,但事实证明我错了,find /i
正在尝试
在文件中搜索(ing)文本字符串并显示找到它的所有行。
(https://ss64.com/nt/find.html)
所以我想我可以更容易地写这个,但是,/usr/ui/^
中的^
符号有什么作用?是正则表达式吗?
EDIT2
@glenn_jackman 似乎确实是对的:也许我最好理解代码要做什么。
所以为了提供更好的上下文,这里是原始批次的更多代码:
for /f "tokens=*" %%a in ('%adb% shell mkdir /usr/ui/^|find /i "File exists"') do (
if not errorlevel 1 goto :cannot_patch
)
:cannot_patch
echo Error: Cannot create directory!
echo Patch is already installed or system files exist and might be overwritten.
choice /m "Do you want to continue"
if errorlevel 2 goto :END
goto :continue_patch
据我了解,代码正在尝试运行 adb shell mkdir
命令,如果失败(抛出“文件存在”错误),它将询问用户是否要继续。
所以在这种情况下,我想真正的问题是尝试编写一个在 SH 中执行相同操作的代码,可能不需要 for 循环。
不过,我正在寻找它......
【问题讨论】:
for /F
循环用于捕获命令行%adb% shell mkdir /usr/ui/|find /i "File exists"
的输出;不确定,但没有$
运算符来处理这些事情吗?
感谢您的反馈。在“某处”使用$
运算符是有意义的。但是......我真的不知道我应该把它放在哪里......另外,我不知道如何替换 "tokens=*"
选项。
这听起来像是一个 XY 问题:退后一步,描述一下你想做什么。看起来您想调用$ADB shell mkdir ...
,然后在目录已经存在的情况下执行一些操作。如果是这种情况,那么在 sh 或 bash 中你根本不需要 for 循环。我不太了解 CMD,但似乎 CMD for
命令旨在执行大量工作,而不仅仅是迭代一系列事物。
没错!请看我的编辑,看看我得出了不使用 for 循环的相同假设(或者至少简化代码,我仍在努力理解它,所以请原谅我)。从主代码中的以下行(我也会将其添加到我的问题中)我读到echo Patch is already installed or system files exist and might be overwritten.
,所以这就是我正在测试的内容。
如果%adb% shell mkdir /usr/ui/
只是用来创建目录,为什么不直接取消错误消息并继续?就像在cmd
中一样,你会做mkdir "D:\some\path" 2> nul
...
【参考方案1】:
for /f "tokens=*" %%a in ('%adb% shell mkdir /usr/ui/^|find /i "File exists"') do (
if not errorlevel 1 goto :cannot_patch
)
运行命令%adb% shell mkdir /usr/ui/
,然后在该输出中搜索字符串File exists
。 if not errorlevel 1
的意思是“如果 %errorlevel% 不大于或等于 1”,这是一种奇怪而尴尬的方式,只是说 if "%errorlevel%"=="0"
,这意味着找到了字符串。如果找到,则脚本将转到标签 :cannot_patch
。
在bash中,处理命令输出的方式是使用$()
而不是for /f
,所以
$($adb shell mkdir /usr/ui/ | grep "File exists") && cannot_patch
这假定变量 adb
已设置,并且您的 shell 脚本中有一个名为 cannot_patch
的函数。
请注意,我的回答与 Paul Hodge's answer 之间的唯一区别是我假设您仍然需要调用 ADB
。
【讨论】:
谢谢!我编辑了问题,插入了一个指向我试图隐藏的完整批处理脚本的链接。是的,确实需要 ADB,因为它连接到我要修补的路由器。我会尽快让你知道我会用你的建议实现什么! 我实际上以不同的方式解决了问题,但您和其他人的回答确实对我帮助很大。抱歉这么晚才回复。我所做的链接:github.com/umbe1987/R216-Z/blob/…【参考方案2】:循环的一般语法匹配https://ss64.com/nt/for.html 您还应该查看https://ss64.com/nt/errorlevel.html 和this SO reference that lists/explains error codes。
来自 SO 文章,FOR /F │ 1 = No data was processed.
但是错误级别页面说
IF ERRORLEVEL 1 will return TRUE whether the errorlevel is 1 or 5 or 64
SO 文章也说
if %errorlevel% equ 5 (
echo Can not access the directory, check rights
)
显然^
是一个 CMD 转义字符,在这里用于转义作为复合命令的一部分传递的管道字符(我猜......)创建一个目录并检查失败,所以我' m 将其解析为尝试创建目录,检测它是否已经存在,并做出相应的响应。
我认为在 bash 中会这样写:
mkdir /usr/ui/ || cannot_patch
【讨论】:
我正在阅读if not errorlevel 1
作为写 if "!errorlevel!"=="0"
的懒惰方式,但我通常不会将 errorelevel 弄乱“0”和“not 0”。【参考方案3】:
抱歉,我有个坏消息要告诉你——你要转录的批处理代码是错误的:
for /f "tokens=*" %%a in ('%adb% shell mkdir /usr/ui/^|find /i "File exists"') do (
if not errorlevel 1 goto :cannot_patch
)
这不会像你想象的那样做。实际上会发生以下步骤:
它执行命令%adb% shell mkdir /usr/ui/
并将其输出通过管道 (|
) 传递到命令 find /i "File exists"
,但所有这些都发生在由 for /F
循环创建的新 cmd.exe
实例中。
for /F
循环,嗯,在上述命令完成后循环输出的行;新的 cmd.exe
实例在开始迭代之前被销毁。
但是:%adb% …|find …
命令行产生的ErrorLevel
值在for /F
循环体中不可用,因为它在cmd.exe
中执行例如批处理脚本本身也在其中运行。这意味着,循环体中的条件if not errorlevel 1
实际上会无意中对前面的 命令做出反应。
因为,我相信,您只是想测试%adb% shell mkdir /usr/ui/
的输出是否以不区分大小写的方式包含子字符串File exists
,您实际上只需要这个:
rem /* Just using `echo` for demonstration purposes, to be replaced;
rem moreover, you may also omit the `&&` or the `||` part: */
%adb% shell mkdir /usr/ui/ | find /i "File exists" && (
echo ErrorLevel 0: sub-string found.
) || (
echo ErrorLevel 1: sub-string NOT found!
)
不幸的是,我无法确切告诉您如何翻译,但 find
可能必须替换为 grep
,并且运算符 &&
和 ||
可以通过检查返回的退出代码来替换$?
,除非有类似的运算符……
【讨论】:
&&
和 ||
在批处理和 bash 中是相同的,幸运的是以上是关于试图将 for /f "tokens=*" %%a in ... 转换为 SHELL的主要内容,如果未能解决你的问题,请参考以下文章