adb shell 复制/移动文件时的转义字符

问题来源

有时候,我们调用Shell命令来完成一些操作会方便点。比如复制文件调用cp 'src' 'dest'命令。但是如果源路径或者目标路径中包含一些Linux Shell 中的一些特殊字符时,可能命令执行的结果并不是我们想要的。此时我们就需要对这些命令进行转义。

Shell中的文件操作

# 复制文件
cp 'src' 'dest'
# 移动文件
mv 'src' 'dest'
# 创建文件
touch 'fileName'
# 创建文件夹
mkdir 'dirName'

如何处理路径特使字符

Shell特殊字符

  • shell通配符(wildcard)
    *,? [] ,{}
  • shell元字符(特殊字符 Meta)
    | & ; ( ) < > space tab
    || & && ; ;; ( ) |
  • shell转义符
    ' , " , \

转义特殊字符的三种方式

  • 单引号'' (硬转义)
    其内部所有的shell 元字符、通配符都会被关掉。注意,硬转义中不允许出现'(单引号)。
  • 双引号"" (软转义)
    其内部只允许出现特定的shell 元字符:$用于参数代换 '用于命令代替
  • 转义 \ (转义)
    去除其后紧跟的元字符或通配符的特殊意义。

怎么选择处理方式

之前我不想匹配那么多特殊字符,使用的是单引号的方式来处理路径中的特殊字符,直到有用户反馈操作一直等待。检查半天发现是他的文件名中有单引号',导致Shell一直在等待下一个'输入。所以呢,单引号是不靠谱的,现在是采用第三种方式。

所以:

  • 如果确认路径不包含特殊字符,可以不转义
  • 如果确认路径不包含单引号',可以硬转义
  • 如果都保证不来,就使用单个字符转义

单个字符全转义的Java实现

/**
 * 将包含特殊Shell字符的字符串 转换成Shell可执行的字符串
 *
 * @author yawei
 * [email protected]
 * @date 18-6-26
 * @see Linux Shell 特殊字符
 */
public class ShellCommandConversionUtils {

    private static final char[] SPECIAL_CHARS = new char[]{'*', '?', '[', ']', '{', '}', ' ', 0x0D, '=',  '>', '<', '|', '&', '(', ')', ';', '!', '\\', '\'', '"'};

    public static String convert(String line) {
        char[] chars = line.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            char c = chars[i];
            for (int j = 0; j < SPECIAL_CHARS.length; j++) {
                if (c == SPECIAL_CHARS[j]) {
                    chars = insert(chars, i);
                    i++;
                }
            }
        }
        return new String(chars);
    }

    private static char[] insert(char[] chars, int index) {
        char[] nChars = new char[chars.length + 1];
        System.arraycopy(chars, 0, nChars, 0, index + 1);
        nChars[index] = '\\';
        System.arraycopy(chars, index, nChars, index + 1, chars.length - index);
        return nChars;
    }

}

优化后的转义实现

时隔一年,再看这个代码,决定优化一下,测试得出性能提升了5倍。20191108。
1.先查找特殊字符(二分法)
2.在合适的位置插入转义字符

public class ShellCommandConversionUtils {

    private static final char[] SPECIAL_CHARS = new char[]{'*', '?', '[', ']', '{', '}', ' ', 0x0D, '=', '>', '<', '|', '&', '(', ')', ';', '!', '\\', '\'', '"'};

    static {
        Arrays.sort(SPECIAL_CHARS);
    }

    public static String convert(String line) {
        char[] srcChars = line.toCharArray();
        int[] specialCharIndexArray = null;
        int specialCharCount = 0;
        //查找需要转义的字符
        for (int i = 0; i < srcChars.length; i++) {
            int binarySearch = Arrays.binarySearch(SPECIAL_CHARS, srcChars[i]);
            if (binarySearch >= 0) {
                if (specialCharIndexArray == null) {
                    specialCharIndexArray = new int[srcChars.length - i];
                }
                specialCharIndexArray[specialCharCount++] = i;
            }
        }
        //插入转义字符
        if (specialCharCount != 0) {
            char[] destChars = new char[srcChars.length + specialCharCount];
            int srcIndex = 0;
            int cpStart = 0;
            for (int i = 0; i < specialCharCount; i++) {
                int len = specialCharIndexArray[i] - cpStart;
                System.arraycopy(srcChars, srcIndex, destChars, srcIndex + i, len);
                destChars[srcIndex + i + len] = '\\';
                cpStart = specialCharIndexArray[i];
                srcIndex += len;
            }
            System.arraycopy(srcChars, srcIndex, destChars, srcIndex + specialCharCount, srcChars.length - srcIndex);
            return new String(destChars);
        } else {
            return line;
        }
    }
}

参考链接:Linux Shell 通配符、元字符、转义符使用实例介绍

你可能感兴趣的:(android)