我们如何使用批处理脚本将所有应用程序从 android(adb) 复制到 PC?

How can we copy all the apps from android(adb) to PC using Batch scripting?

myapps.txt - 包含通过 adb shell pm list packages > myapps.txt

找到的所有包的列表
package:com.flipkart.android
package:com.android.certinstaller
package:com.android.carrierconfig
package:com.reddit.frontpage
package:com.wapi.wapicertmanage
package:com.brave.browser

以下是我在批处理脚本中编写的代码,用于使用 ADB 将所有应用程序从 android 一次性复制到 PC。 其次,我用冒号 (:) 分割我的字符串,例如 -

string1 包含 package 和 string2 包含 com.google.android.youtube

@echo off
setlocal enabledelayedexpansion
for /f "tokens=1* delims=:" %%i in (myapps.txt) do (
    echo j: %%j
    set string2=%%j
    adb shell pm path !string2! > tmp.txt

    set /p new=< tmp.txt
    @echo on
    @echo new: !new!
    @echo off

    set "str=%new%"
    set "string1=%str::=" & set "string3=%"
    del tmp.txt                 REM delete file after reading from it.

    REM creating new folder for each app
    mkdir apps_%input%\%string2%                

    REM pulling app from Android to PC
    adb pull %string3% apps_%input%\%string2%   

    set /a count+=1
    echo Done !count!
)

这是执行 2 次 for 循环后的以下输出

j: com.flipkart.android
new: package:/data/app/com.flipkart.android-XOmoiAws7zOd07eM1nZIlg==/base.apk
A subdirectory or file apps_2\ already exists.
adb: error: failed to stat remote object 'apps_2\': No such file or directory
Done 1
j: com.android.certinstaller
new: package:/system/app/CertInstaller/CertInstaller.apk
A subdirectory or file apps_2\ already exists.
adb: error: failed to stat remote object 'apps_2\': No such file or directory
Done 2

请帮我看看为什么我会得到这个输出。另外apps_2执行前不存在怎么提示已经存在

但是,同样的事情在 cmd 提示符下运行得很好:

mkdir apps_2\com.flipkart.android
adb pull /data/app/com.flipkart.android-XOmoiAws7zOd07eM1nZIlg==/base.apk apps_2\com.flipkart.android

这是我执行后收到的输出

/data/app/com.flipkart.android-XOmoiAws7zOd07eM1nZIlg==/base.apk: 1 file pulled. 33.8 MB/s (12691794 bytes in 0.358s)

批处理文件未按预期工作,因为 delayed expansion 仅用于 FOR 命令块中的部分而非所有环境变量引用。只有环境变量 input 可以在命令块内用 %input% 引用,因为它是唯一在命令块外定义且未在命令块内修改的环境变量。所有其他环境变量在命令块内 defined/modified 并在命令块内引用。因此,除了 input 之外的所有环境变量都必须使用 ! 而不是 %.

来引用

但是,此任务根本不需要使用环境变量。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
if not defined input set "input=1"
set "count=0"
if exist myapps.txt for /F "tokens=2 delims=:" %%I in (myapps.txt) do (
    echo Getting path of app "%%I" ...
    for /F "tokens=2 delims=:" %%J in ('adb.exe shell pm path "%%I" 2^>nul') do (
        echo Path of app %%I is: "%%J"
        rem Creating new folder for each app.
        mkdir "apps_%input%\%%I" 2>nul
        if exist "apps_%input%\%%I\" (
            rem Pulling app from Android to PC.
            echo Pulling app "%%I" to "apps_%input%\%%I" ...
            adb.exe pull "%%J" "apps_%input%\%%I"
            set /A count+=1
        ) else echo ERROR: Failed to create directory: "apps_%input%\%%I\"
    )
)
if %count% == 1 (set "PluralS=") else set "PluralS=s"
echo Pulled %count% app%PluralS% from Android to PC.
endlocal

外层的FORmyapps.txt一行一行读取。由于选项 delims=:,每一行都使用冒号作为分隔符拆分为子字符串。第一个冒号分隔的子字符串始终是 package,这与此任务无关。因此,选项 tokens=2 用于将第二个子字符串 com.flipkart.android 分配给指定的区分大小写的循环变量 I.

内部 FOR 循环在后台启动另一个命令进程,其中 %ComSpec% /c 和括号中的命令行作为附加参数附加。 adb处理后台命令进程STDOUT的输出由FOR捕获并在启动后逐行处理cmd.exeadb 终止后自行关闭。

adb 输出的单行再次使用冒号作为分隔符拆分为子字符串,并再次将第二个子字符串分配给指定的循环变量 J.

接下来创建一个子目录,将应用程序名称作为目录名称,并将错误消息输出重定向到已存在的目录或无法创建的目录,从句柄 STDERR 到设备 NUL 抑制它。

然后对刚刚创建的目录进行存在性检查以验证它是否真的存在,如果存在,应用程序将从 Android 设备拉到 PC。

运行 cmd /? in a command prompt window 的帮助输出在最后一页解释了包含 [= 的文件名(或任何其他参数字符串) 112=] 或这些字符 &()[]{}^=;!'+,`~ 必须用双引号引起来。因此,所有引用当前分配给循环变量 I(应用程序名称)和 J(应用程序路径)的值的参数字符串都包含在 ".

可以删除所有 echo 命令行和最后一个 if 条件,因为它们仅用于在执行批处理文件期间获取一些进度信息。

为了了解使用的命令及其工作原理,请打开 command prompt window,在其中执行以下命令,并仔细阅读为每个命令显示的所有帮助页面。

  • echo /?
  • endlocal /?
  • for /?
  • if /?
  • mkdir /?
  • rem /?
  • set /?
  • setlocal /?

阅读有关 Using command redirection operators 的 Microsoft 文章,了解 2>nul 的解释。重定向运算符 > 必须在 FOR 命令行上使用脱字符 ^ 进行转义,以便在 Windows 命令解释器处理此命令时将其解释为文字字符执行命令 FOR 之前的行,它在后台启动的单独命令进程中执行嵌入式 adb 命令行。