削除・名前変更できないファイル名やフォルダ名をシェルの特殊パラメーターで操作する on NAS via SSH


操作できないファイルやフォルダがある

  • 共有フォルダ上のフォルダやファイルの削除や名前変更などの操作するとエラーが発生する

    例えば macOS の場合は「操作を完了できません。予期しないエラーが起きました(エラーコード-43)」などと表示される。

  • macOS に限らず、ターミナルや SSH 接続して操作しようとするも「そんなファイルやフォルダはない」と言われる。

  • しかし lsls -d では一覧に表示される。sudo 権限で削除しても NG。所有権やアクセス権も問題なさそうであるし、ファイルを開いたり編集・保存はできる。

TS;DR

ls コマンドで対象ファイルに絞り込んだのち、$_ の特殊パラメーター変数を使って操作する

基本的な使い方
$ ls *foo*bar*.mp4 && mv "$_" "ShortAndRightFileOfFooBar.mp4"

ファイルやディレクトリの名前が長すぎたり、"ZWSP" などの不可視文字といった特殊文字や制御コード文字が含まれていると、コピー時に正規化されることがあります。そのため、ペースト時にはオリジナルと異なるファイル名になったことが原因と思われます。

使い方の実例

使い方の実例
$ # 対象ファイルを探す
$ ls -l
file1.mp3
I'm とてつもなく fu ⋆ king-長い file and with spaces しかも日本語ファイル​​🎉.mp4
file3.wav
$ 
$ # 削除できない
$ rm -f "I'm とてつもなく fu ⋆ king-長い file and with spaces しかも日本語ファイル🎉.mp4"
rm: cannot remove `I'm とてつもなく fu ⋆ king-長い file and with spaces しかも日本語ファイル🎉.mp4': No such file or directory
$
$ # 検索結果を対象ファイル1つに絞る
$ ls *file*spaces*.mp4
I'm とてつもなく fu ⋆ king-長い file and with spaces しかも日本語ファイル​​🎉.mp4
$
$ # 特殊変数 $_ にセットされた内容を確認する
$ echo $_
I'm とてつもなく fu ⋆ king-長い file and with spaces しかも日本語ファイル​​🎉.mp4
$
$ # 以上を組み合わせて `mv` コマンドで短くリネーム
$ ls *file*spaces*.mp4 && mv "$_" "I am short and right file.mp4"
I'm とてつもなく fu ⋆ king-長い file and with spaces しかも日本語ファイル​​🎉.mp4
$
$ # リネームの結果確認
$ ls -l
file1.mp3
I am short and right file.mp4
file3.wav
$
$ # 安心して削除
$ rm "I am short and right file.mp4"
$ ls -l
file1.mp3
file3.wav

TL;DR(詳細)

ネットからスクラップしたデータや大きなファイルを、NAS(QNAP)の共有フォルダをマウントして1箇所で管理してます。

長ったらしいファイル名があったので短くしようと finder からファイル操作すると、「操作を完了できません。」エラーが発生するファイルがあることに気づきました。

どうやらファイルを保存する際に、ファイル名をそのままで保存したり、フォルダ名をサイトからコピペしたものを使ったことが原因で、URL がファイル名だったり、特殊文字が含まれた状態で保存してしまったようです。

よく考えずに、横着でコピペするとコピペピピックなことが起きる典型的な例です。

コピペできないコピペピピックなファイル名は特殊パラメーターで操作する

finder などの GUI シェルから操作ができない場合は、ターミナルからシェル操作するのが王道です。

SSH で NAS(QNAP)にログインして ls で表示されたファイルをコピペして rm したのですが、失敗しました。

$ ssh -l user1 NAME_OF_MY_NAS.local
...
[~] # 
[~] # # QNAP で日本語が扱えるようにシェルを ash に変更
[~] # ash

BusyBox v1.01 (2019.01.01-19:01+0000) Built-in shell (ash)
Enter 'help' for a list of built-in commands.

[/root] # 
[/root] # # 削除したいディレクトリに移動
[/root] # cd /share/HDA_DATA/MyFiles
[/share/HDA_DATA/MyFiles] # # ファイル一覧を確認
[/share/HDA_DATA/MyFiles] # ls
file1.mp3
I'm とてつもなく fu ⋆ king-長い file and with spaces しかも日本語ファイル​​🎉.mp4
file3.wav
[/share/HDA_DATA/MyFiles] # # ファイル名をコピペして削除
[/share/HDA_DATA/MyFiles] # rm "I'm とてつもなく fu ⋆ king-長い file and with spaces しかも日本語ファイル​​🎉.mp4"
rm: cannot remove `I'm とてつもなく fu ⋆ king-長い file and with spaces しかも日本語ファイル​​🎉.mp4': No such file or directory

シングルクォートをエスケープしてもダメでした。ターミナル上でコピーすると正規化されるのか、ペーストするとオリジナルのファイル名と変わるため削除できないようです。

「検索したファイル名をコピペせずに、そのまま rmmv コマンドに渡せばいいのでは」と考えたところ、以下の2つの記事を思い出しました。

そして、この2つのテクニックを使って「mv コマンドでファイル名を短くかつ特殊な状態を回避」してから「rm コマンドで削除」すればいいと考え、最終的に以下のように落ち着きました。

$ ls *some*thing*to*hit.txt && mv "$_" "shortname.txt"
...
$ rm shortname.txt
...