web-dev-qa-db-ja.com

bash:スペースを含むファイルの移動

ファイル名にスペースを含む単一のファイルを移動すると、次のように機能します。

$ mv "file with spaces.txt" "new_place/file with spaces.txt"

スペースが含まれている可能性のあるファイルのリストがあり、それらを移動したいと思います。例えば:

$ echo "file with spaces.txt" > file_list.txt
$ for file in $(cat file_list.txt); do mv "$file" "new_place/$file"; done;

mv: cannot stat 'file': No such file or directory
mv: cannot stat 'with': No such file or directory
mv: cannot stat 'spaces.txt': No such file or directory

なぜ最初の例は機能しますが、2番目の例は機能しませんか?どうすれば機能させることができますか?

10
MrJingles87

決してfor foo in $(cat bar)を使用しないでください。これは、一般的に bash pitfall number 1 として知られている古典的な間違いです。代わりに使用する必要があります:

while IFS= read -r file; do mv -- "$file" "new_place/$file"; done < file_list.txt

forループを実行すると、bashは読み取ったものに単語分割を適用します。つまり、a strange blue cloudastrangeblueおよびcloud

$ cat files 
a strange blue cloud.txt
$ for file in $(cat files); do echo "$file"; done
a
strange
blue
cloud.txt

と比較:

$ while IFS= read -r file; do echo "$file"; done < files 
a strange blue cloud.txt

または、 oC を要求した場合でも、

$ cat files | while IFS= read -r file; do echo "$file"; done
a strange blue cloud.txt

したがって、whileループはその入力を読み取り、readを使用して各行を変数に割り当てます。 IFS=は、入力フィールド区切り文字をNULLに設定します*、およびread-rオプションは、バックスラッシュエスケープの解釈を停止します(そのため、\tは、タブではなくスラッシュ+ tとして扱われます)。 mvの後の--は、「-以降はすべて引数ではなくオプションとして扱う」ことを意味します。これにより、-で始まるファイル名を正しく処理できます。


*これはここでは必要ありません。厳密に言えば、このシナリオでの唯一の利点は、先頭または末尾の空白をreadが削除しないことですが、ファイル名を処理する必要がある場合に備えておくとよいでしょう。改行文字を含む、または一般に、任意のファイル名を処理できるようにする必要がある場合。

20
terdon

リストコンテキストのbashのようなPOSIXシェルの$(cat file_list.txt)は、split + glob演算子です(zshsplit部分のみを実行しますあなたが期待するように)。

$IFS(デフォルトでは[〜#〜] spc [〜#〜]、TABおよびNL)の文字で分割し、グロビングを完全にオフにしない限り、グロブ。

ここでは、改行のみで分割し、グロブ部分は不要なので、次のようにする必要があります。

IFS='
' # split on newline only
set -o noglob # disable globbing

for file in $(cat file_list.txt); do # split+glob
  mv -- "$file" "new_place/$file"
done

これには、(while readループよりも)空の行を破棄し、末尾の終了していない行を保持し、mvの標準入力(プロンプトの場合などに必要)を保持するという利点もあります。

ただし、ファイルのコンテンツ全体をメモリに保存する必要があるという欠点もあります(bashzshなどのシェルでは数回)。

一部のシェル(kshzsh、およびより少ない範囲でbash)では、$(<file_list.txt)ではなく$(cat file_list.txt)を使用して最適化できます。

while readループで同等のことを行うには、次のものが必要です。

while IFS= read <&3 -r file || [ -n "$file" ]; do
  {
    [ -n "$file" ] || mv -- "$file" "new_place/$file"
  } 3<&-
done 3< file_list.txt

またはbashを使用:

readarray -t files < file_list.txt &&
for file in "${files[@]}"
  [ -n "$file" ] || mv -- "$file" "new_place/$file"
done

またはzshを使用:

for file in ${(f)"$(<file_list.txt)"}
  mv -- "$file" "new_place/$file"
done

またはGNU mv and zsh

mv -t -- new_place ${(f)"$(<file_list.txt)"}

またはGNU mvおよびGNU xargsおよびksh/zsh/bash:

xargs -rd '\n' -a <(grep . file_list.txt) mv -t -- new_place

bash/POSIXシェルで変数を引用するのを忘れることのセキュリティ上の意味 で展開を引用符で囲まないままにすることの意味の詳細

11

スクリプトを記述する代わりに、find ..を使用できます。

 find -type f -iname \*.txt -print0 | xargs -IF -0 mv F /folder/to/destination/

ファイルがfileにある場合は、次の操作を実行できます。

cat file_with_spaces.txt | xargs -IF -0 mv F /folder/to/destination

二番目はわかりませんが….

幸運を

1
FIRST INSTALL 

apt-get install chromium-browser

apt-get install omxplayer

apt-get install terminator

apt-get install nano (if not already installed)

apt-get install zenity (if not already installed)

THEN CREATE A BASH SCRIPT OF ALL OF THESE PERSONALLY WRITTEN SCRIPTS. 

MAKE SURE THAT EVERY Shell SCRIPT IS A .sh FILE ENDING EACH ONE OF THESE IS SCRIPTED TO OPEN UP A DIRECTORY FOR YOU TO FIND AND PICK WHAT YOU WANT. 

IT RUNS A BACKGROUND TERMINAL & ALLOWS YOU TO CONTROL THE SONG OR MOVIE.  

MOVIE KEYS ARE AS FOLLOWS; p or space bar for pause, q for quit, - & + for sound up and down, left arrow and right arrow for skipping forward and back. 

MUSIC PLAYER REALLY ONLY HAS A SKIP SONG AND THAT IS CTRL+C AND IF THAT IS THE LAST SONG OR ONLY SONG THEN IT SHUTS DOWN AND THE TERMINAL GOES AWAY.


****INSTRUCTIONS TO MAKE THE SCRIPTS****
- OPEN UP A TERMINAL 

- CD TO THE DIRECTORY YOU WANT THE SCRIPTS TO BE
cd /home/pi/Desktop/

- OPEN UP THE NANO EDITOR WITH THE TITLE OF Shell YOU WANT
Sudo nano Movie_Player.sh

- INSIDE NANO, TYPE OR COPY/PAST (REMEMBER THAT IN TERMINAL YOU NEED TO CTRL+SHIFT+V) THE SCRITP

- SAVE THE DATA WITH CTRL+O
ctrl+o

- HIT ENTER TO SAVE AS THAT FILE NAME OR DELETE THE FILE NAME THEN TYPE NEW ONE JUST MAKE SURE IT ENDS IN .sh THEN HIT ENTER

- NEXT YOU NEED TO Sudo CHMOD IT WITH +X TO MAKE IT CLICKABLE AS A BASH
Sudo chmod +x Movie_Player.sh

- FINALLY RUN IT TO TEST EITHER BY DOUBLE CLICKING IT AND CHOOSING "EXECUTE IN TERMINAL" OR BY ./ IT IN TERMINAL
./Movie_Player.sh

YOU ARE NOW GOOD TO PICK A MOVIE OR SELECT A SONG OR ALBUM AND ENJOY!  




**** ALL OF THESE SCRIPTS ACCOUNT FOR SPACES IN THE FILENAME 
SO YOU CAN ACCESS "TOM PETTY" OR "SIXTEEN STONE" WITHOUT NEEDING THE " _ " BETWEEN THE WORDS.




-------WATCH A MOVIE SCRIPT ------- (

#!/ bin/bash

FILE = zenity --title "Pick a Movie" --file-selection

「$ {FILE [0]}」のFILE

omxplayer "$ {FILE [0]}"を実行しました

--------LISTEN TO A SONG -------

!/ bin/bash

FILE = zenity --title "Pick a Song" --file-selection

「$ {FILE [0]}」のFILE

「$ {FILE [0]}」を再生します

--------LISTEN TO AN ALBUM ---------- SONGS IN ORDER

!/ bin/bash

DIR = zenity --title "Pick a Album" --file-selection --directory

「$ {DIR [0]}」のDIR

cd "$ {DIR [0]}" && findを実行します。 -type f -name '。ogg' -o -name '。mp3' | sort --version-sort | DIRの読み取り中。 「$ DIR」を再生します

--------LISTEN TO AN ALBUM WITH SONGS IN RANDOM ORDER --------

!/ bin/bash

DIR = zenity --title "Pick a Album" --file-selection --directory

「$ {DIR [0]}」のDIR

cd "$ {DIR [0]}" && findを実行します。 -type f -name '。ogg' -o -name '。mp3' | DIRの読み取り中。 「$ DIR」を再生します

0
Alfred Gauf