如何将语法高亮添加到包含 Bash 中某些代码的字符串?

How to add syntax highlighting to a string containing some code in Bash?

我有一个包含一些基本 aidl 代码的变量(基本上只是一堆方法签名)。 我想以添加语法突出显示的方式回显该变量。例如用不同颜色显示方法名、数据类型和参数名。

我知道可以这样手工完成:

NC='3[0m' # no color
BLUE='3[0;34m'
RED='3[0;31m'
GREEN='3[0;32m'

# Wihtout syntax highlighting
echo "void verifyIntentFilter(int id, int verificationCode, in List<String> failedDomains);"

# With syntax highlighting
echo "${BLUE}void${NC} ${RED}verifyIntentFilter${NC}(${BLUE}int${NC} ${GREEN}id${NC}, ${BLUE}int${NC} ${GREEN}verificationCode${NC}, ${BLUE}in List<String>${NC} ${GREEN}failedDomains${NC});"

但是有几万行代码一直在变化,我不想一直重写脚本。是否有 Bash 命令来执行此操作?我认为如果有一个命令可以突出显示 Java 或 C++ 代码,那可能会起作用,因为 aidl 方法签名非常相似。

这是我的变量的一个例子:

CODE=$(cat <<-END
void checkPackageStartable(String packageName, int userId);
boolean isPackageAvailable(String packageName, int userId);
PackageInfo getPackageInfo(String packageName, int flags, int userId);
PackageInfo getPackageInfoVersioned(in VersionedPackage versionedPackage,int flags, int userId);
int getPackageUid(String packageName, int flags, int userId);
int[] getPackageGids(String packageName, int flags, int userId);
String[] currentToCanonicalPackageNames(in String[] names);
String[] canonicalToCurrentPackageNames(in String[] names);
PermissionInfo getPermissionInfo(String name, String packageName, int flags);
ParceledListSlice queryPermissionsByGroup(String group, int flags);
PermissionGroupInfo getPermissionGroupInfo(String name, int flags);
ParceledListSlice getAllPermissionGroups(int flags);
ApplicationInfo getApplicationInfo(String packageName, int flags ,int userId);
ActivityInfo getActivityInfo(in ComponentName className, int flags, int userId);
boolean activitySupportsIntent(in ComponentName className, in Intent intent,String resolvedType);
ActivityInfo getReceiverInfo(in ComponentName className, int flags, int userId);
ServiceInfo getServiceInfo(in ComponentName className, int flags, int userId);
ProviderInfo getProviderInfo(in ComponentName className, int flags, int userId);
int checkPermission(String permName, String pkgName, int userId);
int checkUidPermission(String permName, int uid);
boolean addPermission(in PermissionInfo info);
void removePermission(String name);
void grantRuntimePermission(String packageName, String permissionName, int userId);
void revokeRuntimePermission(String packageName, String permissionName, int userId);
void resetRuntimePermissions();
int getPermissionFlags(String permissionName, String packageName, int userId);
void updatePermissionFlags(String permissionName, String packageName, int flagMask,int flagValues, int userId);
void updatePermissionFlagsForAllApps(int flagMask, int flagValues, int userId);
boolean shouldShowRequestPermissionRationale(String permissionName,String packageName, int userId);
boolean isProtectedBroadcast(String actionName);
int checkSignatures(String pkg1, String pkg2);
int checkUidSignatures(int uid1, int uid2);
List<String> getAllPackages();
String[] getPackagesForUid(int uid);
String getNameForUid(int uid);
String[] getNamesForUids(in int[] uids);
int getUidForSharedUser(String sharedUserName);
int getFlagsForUid(int uid);
int getPrivateFlagsForUid(int uid);
boolean isUidPrivileged(int uid);
String[] getAppOpPermissionPackages(String permissionName);
ResolveInfo resolveIntent(in Intent intent, String resolvedType, int flags, int userId);
ResolveInfo findPersistentPreferredActivity(in Intent intent, int userId);
boolean canForwardTo(in Intent intent, String resolvedType, int sourceUserId, int targetUserId);
ParceledListSlice queryIntentActivities(in Intent intent,String resolvedType, int flags, int userId);
ParceledListSlice queryIntentActivityOptions(in ComponentName caller, in Intent[] specifics,in String[] specificTypes, in Intent intent,String resolvedType, int flags, int userId);
ParceledListSlice queryIntentReceivers(in Intent intent,String resolvedType, int flags, int userId);
ResolveInfo resolveService(in Intent intent,String resolvedType, int flags, int userId);
ParceledListSlice queryIntentServices(in Intent intent,String resolvedType, int flags, int userId);
ParceledListSlice queryIntentContentProviders(in Intent intent,String resolvedType, int flags, int userId);
ParceledListSlice getInstalledPackages(int flags, in int userId);
ParceledListSlice getPackagesHoldingPermissions(in String[] permissions,int flags, int userId);
ParceledListSlice getInstalledApplications(int flags, int userId);
ParceledListSlice getPersistentApplications(int flags);
ProviderInfo resolveContentProvider(String name, int flags, int userId);
void querySyncProviders(inout List<String> outNames,inout List<ProviderInfo> outInfo);
ParceledListSlice queryContentProviders(String processName, int uid, int flags, String metaDataKey);
InstrumentationInfo getInstrumentationInfo(in ComponentName className, int flags);
ParceledListSlice queryInstrumentation(String targetPackage, int flags);
void finishPackageInstall(int token, boolean didLaunch);
void setInstallerPackageName(in String targetPackage, in String installerPackageName);
void setApplicationCategoryHint(String packageName, int categoryHint, String callerPackageName);
void deletePackageAsUser(in String packageName, int versionCode,IPackageDeleteObserver observer, int userId, int flags);
void deletePackageVersioned(in VersionedPackage versionedPackage,IPackageDeleteObserver2 observer, int userId, int flags);
String getInstallerPackageName(in String packageName);
void resetApplicationPreferences(int userId);
ResolveInfo getLastChosenActivity(in Intent intent,String resolvedType, int flags);
void setLastChosenActivity(in Intent intent, String resolvedType, int flags,in IntentFilter filter, int match, in ComponentName activity);
void addPreferredActivity(in IntentFilter filter, int match,in ComponentName[] set, in ComponentName activity, int userId);
void replacePreferredActivity(in IntentFilter filter, int match,in ComponentName[] set, in ComponentName activity, int userId);
void clearPackagePreferredActivities(String packageName);
int getPreferredActivities(out List<IntentFilter> outFilters,out List<ComponentName> outActivities, String packageName);
void addPersistentPreferredActivity(in IntentFilter filter, in ComponentName activity, int userId);
void clearPackagePersistentPreferredActivities(String packageName, int userId);
void addCrossProfileIntentFilter(in IntentFilter intentFilter, String ownerPackage,int sourceUserId, int targetUserId, int flags);
void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage);
String[] setPackagesSuspendedAsUser(in String[] packageNames, boolean suspended,in PersistableBundle appExtras, in PersistableBundle launcherExtras,String dialogMessage, String callingPackage, int userId);
boolean isPackageSuspendedForUser(String packageName, int userId);
PersistableBundle getSuspendedPackageAppExtras(String packageName, int userId);
byte[] getPreferredActivityBackup(int userId);
void restorePreferredActivities(in byte[] backup, int userId);
byte[] getDefaultAppsBackup(int userId);
void restoreDefaultApps(in byte[] backup, int userId);
byte[] getIntentFilterVerificationBackup(int userId);
void restoreIntentFilterVerification(in byte[] backup, int userId);
byte[] getPermissionGrantBackup(int userId);
void restorePermissionGrants(in byte[] backup, int userId);
ComponentName getHomeActivities(out List<ResolveInfo> outHomeCandidates);
void setHomeActivity(in ComponentName className, int userId);
void setComponentEnabledSetting(in ComponentName componentName,in int newState, in int flags, int userId);
int getComponentEnabledSetting(in ComponentName componentName, int userId);
void setApplicationEnabledSetting(in String packageName, in int newState, int flags,int userId, String callingPackage);
int getApplicationEnabledSetting(in String packageName, int userId);
void logAppProcessStartIfNeeded(String processName, int uid, String seinfo, String apkFile,int pid);
void flushPackageRestrictionsAsUser(in int userId);
void setPackageStoppedState(String packageName, boolean stopped, int userId);
void freeStorageAndNotify(in String volumeUuid, in long freeStorageSize,int storageFlags, IPackageDataObserver observer);
void freeStorage(in String volumeUuid, in long freeStorageSize,int storageFlags, in IntentSender pi);
void deleteApplicationCacheFiles(in String packageName, IPackageDataObserver observer);
void deleteApplicationCacheFilesAsUser(in String packageName, int userId, IPackageDataObserver observer);
void clearApplicationUserData(in String packageName, IPackageDataObserver observer, int userId);
void clearApplicationProfileData(in String packageName);
void getPackageSizeInfo(in String packageName, int userHandle, IPackageStatsObserver observer);
String[] getSystemSharedLibraryNames();
ParceledListSlice getSystemAvailableFeatures();
boolean hasSystemFeature(String name, int version);
void enterSafeMode();
boolean isSafeMode();
void systemReady();
boolean hasSystemUidErrors();
void performFstrimIfNeeded();
void updatePackagesIfNeeded();
oneway void notifyPackageUse(String packageName, int reason);
oneway void notifyDexLoad(String loadingPackageName, in List<String> classLoadersNames,in List<String> classPaths, String loaderIsa);
oneway void registerDexModule(in String packageName, in String dexModulePath,in boolean isSharedModule, IDexModuleRegisterCallback callback);
boolean performDexOptMode(String packageName, boolean checkProfiles,String targetCompilerFilter, boolean force, boolean bootComplete, String splitName);
boolean performDexOptSecondary(String packageName,String targetCompilerFilter, boolean force);
void dumpProfiles(String packageName);
void forceDexOpt(String packageName);
boolean runBackgroundDexoptJob(in List<String> packageNames);
void reconcileSecondaryDexFiles(String packageName);
PackageCleanItem nextPackageToClean(in PackageCleanItem lastPackage);
int getMoveStatus(int moveId);
void registerMoveCallback(in IPackageMoveObserver callback);
void unregisterMoveCallback(in IPackageMoveObserver callback);
int movePackage(in String packageName, in String volumeUuid);
int movePrimaryStorage(in String volumeUuid);
boolean addPermissionAsync(in PermissionInfo info);
boolean setInstallLocation(int loc);
int getInstallLocation();
int installExistingPackageAsUser(String packageName, int userId, int installFlags,int installReason);
void verifyPendingInstall(int id, int verificationCode);
void extendVerificationTimeout(int id, int verificationCodeAtTimeout, long millisecondsToDelay);
void verifyIntentFilter(int id, int verificationCode, in List<String> failedDomains);
int getIntentVerificationStatus(String packageName, int userId);
boolean updateIntentVerificationStatus(String packageName, int status, int userId);
ParceledListSlice getIntentFilterVerifications(String packageName);
ParceledListSlice getAllIntentFilters(String packageName);
boolean setDefaultBrowserPackageName(String packageName, int userId);
String getDefaultBrowserPackageName(int userId);
VerifierDeviceIdentity getVerifierDeviceIdentity();
boolean isFirstBoot();
boolean isOnlyCoreApps();
boolean isUpgrade();
void setPermissionEnforced(String permission, boolean enforced);
boolean isPermissionEnforced(String permission);
boolean isStorageLow();
boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden, int userId);
boolean getApplicationHiddenSettingAsUser(String packageName, int userId);
void setSystemAppHiddenUntilInstalled(String packageName, boolean hidden);
boolean setSystemAppInstallState(String packageName, boolean installed, int userId);
IPackageInstaller getPackageInstaller();
boolean setBlockUninstallForUser(String packageName, boolean blockUninstall, int userId);
boolean getBlockUninstallForUser(String packageName, int userId);
KeySet getKeySetByAlias(String packageName, String alias);
KeySet getSigningKeySet(String packageName);
boolean isPackageSignedByKeySet(String packageName, in KeySet ks);
boolean isPackageSignedByKeySetExactly(String packageName, in KeySet ks);
void addOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
void removeOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
void grantDefaultPermissionsToEnabledCarrierApps(in String[] packageNames, int userId);
void grantDefaultPermissionsToEnabledImsServices(in String[] packageNames, int userId);
void grantDefaultPermissionsToEnabledTelephonyDataServices(in String[] packageNames, int userId);
void revokeDefaultPermissionsFromDisabledTelephonyDataServices(in String[] packageNames, int userId);
void grantDefaultPermissionsToActiveLuiApp(in String packageName, int userId);
void revokeDefaultPermissionsFromLuiApps(in String[] packageNames, int userId);
boolean isPermissionRevokedByPolicy(String permission, String packageName, int userId);
String getPermissionControllerPackageName();
ParceledListSlice getInstantApps(int userId);
byte[] getInstantAppCookie(String packageName, int userId);
boolean setInstantAppCookie(String packageName, in byte[] cookie, int userId);
Bitmap getInstantAppIcon(String packageName, int userId);
boolean isInstantApp(String packageName, int userId);
boolean setRequiredForSystemUser(String packageName, boolean systemUserApp);
void setUpdateAvailable(String packageName, boolean updateAvaialble);
String getServicesSystemSharedLibraryPackageName();
String getSharedSystemSharedLibraryPackageName();
ChangedPackages getChangedPackages(int sequenceNumber, int userId);
boolean isPackageDeviceAdminOnAnyUser(String packageName);
int getInstallReason(String packageName, int userId);
ParceledListSlice getSharedLibraries(in String packageName, int flags, int userId);
boolean canRequestPackageInstalls(String packageName, int userId);
void deletePreloadsFileCache();
ComponentName getInstantAppResolverComponent();
ComponentName getInstantAppResolverSettingsComponent();
ComponentName getInstantAppInstallerComponent();
String getInstantAppAndroidId(String packageName, int userId);
IArtManager getArtManager();
void setHarmfulAppWarning(String packageName, CharSequence warning, int userId);
CharSequence getHarmfulAppWarning(String packageName, int userId);
boolean hasSigningCertificate(String packageName, in byte[] signingCertificate, int flags);
boolean hasUidSigningCertificate(int uid, in byte[] signingCertificate, int flags);
String getSystemTextClassifierPackageName();
boolean isPackageStateProtected(String packageName, int userId);
END
)

编辑:

使用 highlight 命令,我可以让语法高亮显示在一定程度上起作用,但它不能识别很多数据类型。例如,它适用于 booleanintbyte,但不适用于 StringComponentNameIOnPermissionsChangeListener 等。 .

echo "$CODE" | highlight --out-format=xterm256 --syntax=java

似乎更可靠的方法是使用某种正则表达式替换来逐行添加颜色。 例如

但我想不出在 Bash 中实现它的合理方法。

I'm asking for a solution to a problem

步骤:

  1. 为您要解析的语法编写一个解析器。最好使用真正的编程语言,如 python 或 C++。标记输入并检测标记类型(函数 return 类型、函数标识符、参数类型、参数标识符等)。
  2. 将特定颜色应用于特定标记类型。
  3. 输出。

I can't think of a reasonable way to implement this in Bash.

我也想不出来,我相信,因为在 bash 中有 none 合理的方法来做到这一点。 Bash 是一种 shell,它不是一种完全易于使用的编程语言,速度也不快,它是一种 shell,主要用于 运行 其他 程序。考虑一种不同的语言。你可以瞄准 awk,但我会选择 python。

对于简单的情况,您可以将其写在正则表达式中。在 sedawk 中(仍然 - 而不是 bash)并用一些正则表达式标记输入,应用颜色和输出,但我不相信你将能够处理前。 C++ 中的函数指针。

sed 编写的分词器示例,仅供娱乐:

echo 'void checkPackageStartable(String packageName, int userId);' |
sed '
    s/^ *\([^(,)]\+\) \+\([^ (,)]\+\)\([(,)]\)\(.*\)/\n{FUNCRET}\n{FUNCNAME}\n{SEP}\n/;
    h;
    :a; {
        /^ *\([^(,)]\+\) \+\([^ (,)]\+\)\([(,)]\)\([^\n]*\)\n\(.*\)$/{
            s//\n{PARTYPE}\n{PARNAME}\n{SEP}\n/
            b a
        }
    }
    s/^;\(.*\)/{END};/
'

输出:

{FUNCRET}void
{FUNCNAME}checkPackageStartable
{SEP}(
{PARTYPE}String
{PARNAME}packageName
{SEP},
{PARTYPE}int
{PARNAME}userId
{SEP})
{END};

您可以修改此类 sed 脚本以应用来自某些变量的颜色而不是标记,并将输出中的换行符更改为空格以用于您请求的输出。