Windows 使用短文件名删除 “无法找到指定文件” 的文件夹

最近 Windows 7 桌面上有几个文件夹,其中一个文件夹名称为:“2023.05.08 【POC】某司POC”。每次尝试删除时都会提示“系统找不到指定的文件”,而且无论是通过右键删除,还是使用命令提示符,都无法成功。

image-20240923上午84809860

经过排查,发现可能是由于文件夹名中包含空格、特殊字符(比如【】)等导致的。Windows某些情况下会无法正确识别带有特殊字符或过长的路径文件,导致删除失败。

解决思路

Windows 文件系统有个特性:8.3文件名。8.3文件名(或简称8.3)是FAT文件系统的一种文件命名规范。 在与“长文件名”并称时可以称为短文件名。 广泛影响于采用FAT文件系统且不支持VFAT的DOS和Windows操作系统(如Windows 95、Windows NT 3.5及以前的版本)中。

这是一种兼容DOS时代遗留的文件命名机制,允许文件使用简短的名字。通过这个特性,可以绕过空格和特殊字符的问题,成功删除文件夹。

操作步骤

第一步:进入文件夹所在目录
  1. 打开命令提示符(以管理员身份运行)。
  2. 通过 cd 命令进入文件所在的目录。

    cd "C:\Users\YourUsername\Desktop"
    
第二步:查看文件夹的短文件名
  1. 在命令提示符中,使用 dir /x 命令列出目录中的所有文件和文件夹,同时显示它们的短文件名(8.3格式):

    dir /x
    
  2. 输出结果会显示文件夹的短名称。例如,我的文件夹“2023.05.08 【POC】阿里 POC” 对应的短文件名是 “202305~1.08” 这样的格式。短文件名的长度通常是前6个字符加上一个数字后缀。

第三步:删除文件夹
  1. 找到短文件名后,使用 rd 命令删除文件夹。仍然使用我的文件夹为例:

    rd /s /q 202305~1.08
    
    • /s:删除文件夹及其所有子文件和子文件夹。
    • /q:安静模式,不提示确认直接删除。

    如果是文件,用这个命令:

    del /f /q 202305~1.08
    
  2. 执行这个命令后,文件夹成功被删除。

参考资料


将 Homebrew 安装的 MacVim 显示在 `/Applications` 文件夹中

在 macOS 上使用 Homebrew 安装软件时,应用程序通常会存放在 Homebrew 的专用目录下,不会自动出现在系统的 /Applications 文件夹中。本文记录将 Homebrew 安装的 MacVim.app 添加到 /Applications 文件夹中。

方法一:手动创建符号链接

  1. 首先,确定 Homebrew 安装的 MacVim.app 的路径:

    which mvim
    

    一般位于 /opt/homebrew/Cellar/macvim/9.1.0727/ 的路径。

  2. 进入终端后,使用 ln 命令创建符号链接:

    ln -s /opt/homebrew/Cellar/macvim/9.1.0727/MacVim.app /Applications/MacVim.app
    

注意:当 macvim 版本更新时,路径可能会发生变化,届时需要根据新路径再次创建符号链接。

方法二:手动复制 .app 文件

  1. 打开终端并运行以下命令:

    cp -r /opt/homebrew/Cellar/macvim/9.1.0727/MacVim.app /Applications/
    

方法三:使用 brew install --cask macvim

对于那些想让 Homebrew 自动管理应用程序,并直接将 .app 文件安装到 /Applications 的用户,推荐使用 Homebrew 的 cask 版本。

Cask 是 Homebrew 提供的一个扩展,专门用于安装 macOS GUI 应用程序。通过使用 cask,可以避免手动创建符号链接或复制应用程序,Homebrew 会自动将应用程序安装到 /Applications

  1. 首先,卸载通过 Homebrew 正常安装的 macvim

    brew uninstall macvim
    
  2. 然后使用 cask 安装 macvim

    brew install --cask macvim
    

    这样,MacVim.app 会自动安装到 /Applications,无需手动干预。


在 macOS Finder 中显示隐藏文件和文件夹

在 macOS 中,有些文件和文件夹是默认隐藏的,例如系统文件和配置文件。Finder 默认不显示它们。但需要访问这些隐藏文件,比如 `/opt/homebrew/,就令人头大了。

使用快捷键显示隐藏文件

  1. 打开 Finder:确保在桌面或打开的 Finder 窗口中。
  2. 使用快捷键:按下 Command + Shift + . (点号)。这个组合键会立即显示或隐藏隐藏的文件和文件夹。

image-20240922上午114353078

永久显示隐藏文件

如果经常需要访问隐藏文件,可以考虑永久显示它们:

  1. 打开终端
  2. 输入以下命令
    defaults write com.apple.finder AppleShowAllFiles -bool true
    
  3. 重启 Finder:输入命令:
    killall Finder
    
  4. 查看文件:现在,Finder 中的所有隐藏文件和文件夹都将始终可见。

要恢复默认设置,可以将 true 替换为 false,并再次重启 Finder。


Windows 7 安装 openssh 服务

最近在 win7 上安装了 openssh 服务端,记录一下过程,微软官方有支持的。

  1. 下载 OpenSSH for Windows

    下载最新的 OpenSSH for Windows二进制文件 <https://github.com/PowerShell/Win32-OpenSSH/releases/

    下载OpenSSH-Win64.zip或OpenSSH-Win32.zip。我下载的这个:OpenSSH-Win64.zip

  2. 解压缩文件

    作为管理员,将包解压缩到%PROGRAMFILES%\OpenSSH。(注意:文件夹必须命名为“OpenSSH”)

  3. 手动安装 OpenSSH

    以管理员身份打开PowerShell(右键单击PowerShell图标,“以管理员身份运行”)

    手动安装注入信息。

     > cd "%PROGRAMFILES%\OpenSSH"
     > powershell.exe -ExecutionPolicy Bypass -File install-sshd.ps
    

    这个命令将会安装 SSHD 服务,并将其注册到系统服务中。

    image-20240923上午64857570

  4. 配置防火墙

    “控制面板”>“系统和安全”>“Windows防火墙”>“高级设置”>“入站规则”,然后为端口22添加新规则。

  5. 启动并配置 SSHD 服务自启动

    • 转到“控制面板”>“系统和安全”>“管理工具”,然后打开“服务”。找到sshd服务。
    • 自启动:转到“操作”>“属性”。在“属性”对话框中,将“启动类型”更改为“自动”并确认。
    • 单击“启动服务”以启动sshd服务。
  6. 设置用户 SSH 密钥

    在C:\Users<用户>.ssh下创建~./ssh文件夹

    在~./.ssh下创建文件“authorized_keys”

  7. 修复权限问题

    有时在 Windows 环境下,文件权限可能不正确。可以通过以下命令来修复这些权限:

    > powershell.exe -ExecutionPolicy Bypass -File FixHostFilePermissions.ps1
    

    image-20240923上午65101752

  8. 个性化SSH服务器设置,编辑配置文件%PROGRAMDATA%\ssh\sshd_config。修改完成后记得重启 sshd 服务。

11726972758.pic

参考资料


Windows 批量关闭进程

taskkill /F /IM putty.exe /T
taskkill /F /IM chrome.exe /T
  • /F:表示强制关闭进程
  • /IM:指定进程名称,这里是 putty.exe
  • /T:终止指定进程以及该进程创建的所有子进程

这些命令其实不容易敲,windows cmd 也没有历史记录这一说,保存成bat文件点击使用更好一些。


从 AppleScript 到 Swift Playground:解决导出日历备注的问题

最近在项目中,遇到了一个问题:从 macOS 的日历应用中导出特定事件的备注内容。

使用 AppleScript

先前用的是 AppleScript:《在 Mac 上将当天的日历事项导出为 TXT 文件》,通过脚本直接访问并提取 iCloud 日历。然而, AppleScript 对于访问日历中部分事件的属性,特别是“备注”字段,无法访问,例如:

-- 设置目标日历和事件名称
set targetCalendar to "日常" -- iCloud 中的日常列表
set targetEventTitle to "A1-今日重点工作安排"

-- 获取今天的日期
set currentDate to current date
set todayStart to currentDate - (time of currentDate)
set todayEnd to todayStart + 1 * days

-- 查找日历中的事件
tell application "Calendar"
	set theCalendar to calendar targetCalendar
	set theEvents to (every event of theCalendar whose summary is targetEventTitle and start date is greater than or equal to todayStart and start date is less than todayEnd)
	
	if (count of theEvents) > 0 then
		set theEvent to item 1 of theEvents
		
		-- 初始化存储详细信息的字符串
		set eventDetails to ""
		
		-- 获取已知属性并打印
		try
			set eventDetails to eventDetails & "标题: " & (get summary of theEvent) & return
		on error
			set eventDetails to eventDetails & "标题: 无法获取" & return
		end try
		
		try
			set eventDetails to eventDetails & "开始时间: " & (get start date of theEvent) & return
		on error
			set eventDetails to eventDetails & "开始时间: 无法获取" & return
		end try
		
		try
			set eventDetails to eventDetails & "结束时间: " & (get end date of theEvent) & return
		on error
			set eventDetails to eventDetails & "结束时间: 无法获取" & return
		end try
		
		try
			set eventDetails to eventDetails & "位置: " & (get location of theEvent) & return
		on error
			set eventDetails to eventDetails & "位置: 无法获取" & return
		end try
		
		try
			set eventDetails to eventDetails & "备注: " & (get notes of theEvent) & return
		on error
			set eventDetails to eventDetails & "备注: 无法获取" & return
		end try
		
		try
			set eventDetails to eventDetails & "是否为全天事件: " & (get allday event of theEvent) & return
		on error
			set eventDetails to eventDetails & "是否为全天事件: 无法获取" & return
		end try
		
		try
			set eventDetails to eventDetails & "创建日期: " & (get creation date of theEvent) & return
		on error
			set eventDetails to eventDetails & "创建日期: 无法获取" & return
		end try
		
		try
			set eventDetails to eventDetails & "最后修改日期: " & (get modification date of theEvent) & return
		on error
			set eventDetails to eventDetails & "最后修改日期: 无法获取" & return
		end try
		
		try
			set eventDetails to eventDetails & "参与者: " & (get attendees of theEvent) & return
		on error
			set eventDetails to eventDetails & "参与者: 无法获取" & return
		end try
		
		try
			set eventDetails to eventDetails & "事件状态: " & (get status of theEvent) & return
		on error
			set eventDetails to eventDetails & "事件状态: 无法获取" & return
		end try
		
		try
			set eventDetails to eventDetails & "URL: " & (get url of theEvent) & return
		on error
			set eventDetails to eventDetails & "URL: 无法获取" & return
		end try
		
		-- 打印所有事件详细信息到控制台
		log eventDetails
		
	else
		log "未找到今日的相关事件"
	end if
end tell

这个脚本试图通过 get notes of theEvent 获取事件备注,但在实际运行过程中,无论如何修改和调整脚本,依然无法成功获取“备注”这一字段。AppleScript 在处理日历中某些复杂的事件属性时,可能存在一些限制。

AppleScript 进一步探索的失败

我尝试了各种不同的获取方法,包括导出事件的其他属性(如标题、开始和结束时间等)。但对于最关心的“备注”内容,AppleScript 就无法获得。最终,我不得不考虑其他替代方案。

image-20240906下午73228179

转向 Swift Playground

在 AppleScript 行不通的情况下,我决定使用 Swift,在 Swift Playground 里开发和测试都挺方便。Swift 提供了对 EventKit 框架的支持,访问日历事件比较灵活和强大。以下是我使用 Swift Playground 成功提取日历事件的代码:

import EventKit
import Foundation

// 创建事件存储对象
let eventStore = EKEventStore()

// 请求访问权限
eventStore.requestAccess(to: .event) { granted, error in
    if granted {
        // 获取当前日期范围
        let now = Date()
        let calendar = Calendar.current
        let startDate = calendar.startOfDay(for: now)
        let endDate = calendar.date(byAdding: .day, value: 1, to: startDate)!

        // 查找事件
        let predicate = eventStore.predicateForEvents(withStart: startDate, end: endDate, calendars: nil)
        let events = eventStore.events(matching: predicate)
        
        // 查找目标事件
        for event in events {
            if event.title == "A1-今日重点工作安排" {
                // 打印事件详细信息
                print("标题: \(event.title ?? "无标题")")
                print("开始时间: \(event.startDate)")
                print("结束时间: \(event.endDate)")
                print("位置: \(event.location ?? "无")")
                print("备注: \(event.notes ?? "无备注")")
                // 处理 URL
                if let url = event.url {
                    print("URL: \(url)")
                } else {
                    print("URL: 无")
                }
            }
        }
    } else {
        print("访问事件存储失败: \(error?.localizedDescription ?? "未知错误")")
    }
}

通过 Swift 中的 EKEventStore,我得以轻松访问事件的所有详细信息,包括标题、开始时间、结束时间、位置以及我们之前一直无法获取的“备注”内容。

输出备注到文件

为了进一步扩展功能,我将获取到的备注信息保存到了桌面的文本文件中,方便后续查看和使用。以下是最终代码:

import EventKit
import PlaygroundSupport

// 允许 Playground 执行异步代码
PlaygroundPage.current.needsIndefiniteExecution = true

// 创建事件存储对象
let eventStore = EKEventStore()

// 请求完全访问权限
eventStore.requestFullAccessToEvents { granted, error in
    if granted {
        // 获取当前日期范围
        let now = Date()
        let calendar = Calendar.current
        let startDate = calendar.startOfDay(for: now)
        let endDate = calendar.date(byAdding: .day, value: 1, to: startDate)!

        // 查找事件
        let predicate = eventStore.predicateForEvents(withStart: startDate, end: endDate, calendars: nil)
        let events = eventStore.events(matching: predicate)
        
        // 查找目标事件
        var notesArray: [String] = []
        
        for event in events {
            if event.title == "A1-今日重点工作安排" {
                // 获取备注内容
                let notes = event.notes ?? "无备注"
                // 将备注按行拆分并添加到数组中
                let lines = notes.split(separator: "\n").map { String($0) }
                notesArray.append(contentsOf: lines)
            }
        }

        if !notesArray.isEmpty {
            // 构造标题
            let header = "共\(notesArray.count)个重点+遗留工作:\n"
            
            // 添加序号到每个事项
                        let numberedNotes = notesArray.enumerated().map { index, note in
                            let number = String(format: "%02d", index + 1)
                            return "\(number). \(note)"
                        }.joined(separator: "\n")
                        
                        // 将标题和编号内容组合
                        let combinedNotes = header + numberedNotes
            
            // 将标题和备注内容组合
            // let combinedNotes = header + notesArray.joined(separator: "\n")
            
            // 输出到控制台
            print(combinedNotes)
            
            // 获取当前日期并格式化为 YYYY-MM-DD
            let dateFormatter = DateFormatter()
            dateFormatter.dateFormat = "yyyy-MM-dd"
            let dateString = dateFormatter.string(from: now)
                        
            // 设置文件名
            let fileName = "keytask-\(dateString).txt"
            
            // 将内容写入到桌面文件
            let fileManager = FileManager.default
            let desktopURL = fileManager.urls(for: .desktopDirectory, in: .userDomainMask).first!
            let fileURL = desktopURL.appendingPathComponent(fileName)
            
            do {
                try combinedNotes.write(to: fileURL, atomically: true, encoding: .utf8)
                print("备注内容已成功写入到文件: \(fileURL.path)")
            } catch {
                print("写入文件失败: \(error.localizedDescription)")
            }
        } else {
            print("未找到目标事件的备注内容")
        }
    } else {
        print("访问事件存储失败: \(error?.localizedDescription ?? "未知错误")")
    }

    // 完成 Playground 执行
    PlaygroundPage.current.finishExecution()
}

image-20240906下午73735483

总结

虽然 AppleScript 在处理简单的日历自动化任务时依然是一个很好的选择,但在涉及更复杂的日历事件属性时,它的局限性也显现了出来。这个案例也证明了在 macOS 上,面对复杂自动化需求时,Swift 提供了更强大的解决方案。


将本地 Windows 文件夹同步到远程服务器

这个脚本使用 PSCP 和 Plink 工具,PSCP 用于文件传输,Plink 可以用来执行远程命令。确保已安装 PuTTY 工具包中的 PSCP 和 Plink 工具,并将其路径添加到系统的环境变量中。

@echo off

:: 定义本地文件夹和远程服务器信息
set LOCAL_DIR=C:\Workspace\online\
set REMOTE_SERVER=user@1.2.3.4
set REMOTE_DIR=/kelutmp
set PASSWORD=password

:: 检查本地文件夹是否存在
if not exist "%LOCAL_DIR%" (
    echo Local directory does not exist: %LOCAL_DIR%
    exit /b
)

:: 检查本地文件夹是否为空
for /F "delims=" %%F in ('dir /b "%LOCAL_DIR%"') do set NON_EMPTY=1
if not defined NON_EMPTY (
    echo Local directory is empty: %LOCAL_DIR%
    exit /b
)

set FILE_COUNT=0
for /r "%LOCAL_DIR%" %%f in (*) do set /a FILE_COUNT+=1

if "%FILE_COUNT%"=="0" (
    echo Local directory is empty: %LOCAL_DIR%
    exit /b
)

:: 使用 pscp 将本地文件夹中的所有文件同步到远程服务器
pscp -r -pw "%PASSWORD%" "%LOCAL_DIR%*" %REMOTE_SERVER%:%REMOTE_DIR%

:: 如果同步成功,清空本地文件夹
if %errorlevel%==0 (
    echo Sync successful, clearing local directory: %LOCAL_DIR%
    rmdir /s /q "%LOCAL_DIR%"
    mkdir "%LOCAL_DIR%"
) else (
    echo Sync failed, local directory not cleared.
)