mp3 파일을 디렉토리에서 플래시 드라이브로 복사하고 싶습니다. 이는 다음 디렉토리 구조에 저장됩니다: Artist/Album/Track.mp3
. 내 자동차의 mp3 플레이어가 형편없기 때문에 플래시 드라이브의 루트 디렉토리에 파일 이름이 Artist-Album-Track.mp3
.
답변1
for
매개변수 확장을 통해 다양한 요소를 추출하는 간단한 루프가 이를 수행합니다.
for file in */*/*.mp3;
do
artist=${file%%/*}
rest=${file#*/}
album=${rest%%/*}
track=${rest#*/*}
cp -- "$file" /flash/drive/"${artist}-${album}-${track}"
done
첫 번째 확장은 파일 끝부터 첫 번째 슬래시(생성된 아티스트)까지 모든 것을 제거합니다.
두 번째 확장팩이 제거되었습니다.선두첫 번째 슬래시까지의 문자 - 경로에서 아티스트를 제거합니다.
세 번째 확장은 첫 번째 확장과 유사하며, 나머지 경로에서 파일 이름을 제거하고 앨범을 떠납니다.
네 번째 확장팩은 두 번째 확장팩과 유사하며, 앨범을 제거하고 파일 이름만 남깁니다.
그런 다음 이를 모두 함께 대시하고 원하는 /flash/drive 경로에 연결합니다.
답변2
다음 위치 에서 파일 사용 find
및 복사 :bash
$mp3dir
$destdir
mp3dir="$HOME/my_music"
destdir="/mnt/my_mp3_player"
find "$mp3dir" -type f -name '*.mp3' -exec bash -c '
mp3dir=$1; destdir=$2; shift 2
for pathname do
dest=${pathname#$mp3dir/}
dest="$destdir/${dest//\//-}"
if [ -f "$dest" ]; then
printf "%s exist, skipping %s\n" "$dest" "$pathname" >&2
else
cp "$pathname" "$dest"
fi
done' bash "$mp3dir" "$destdir" {} +
$mp3dir
로 시작하는 이름을 찾습니다 .mp3
. 이러한 배치의 경우 짧은 스크립트가 실행됩니다. 이 스크립트의 두 매개 변수는 $mp3dir
및 $destdir
나머지 매개 변수는 MP3 파일의 경로 이름입니다.
스크립트는 처음 두 개의 명령줄 인수에서 두 개의 디렉터리 이름을 선택한 다음 나머지 인수를 반복하여 $dest
각 MP3 파일의 대상 경로 이름을 만듭니다. 이는 bash
경로 이름의 초기 비트를 제거한 후 경로 이름의 모든 슬래시를 대시로 바꾸는 매개변수 대체를 사용하여 수행됩니다 .$mp3dir
이미 존재하는 경우 $dest
이 파일에 대한 메시지가 인쇄되고, 그렇지 않으면 복사됩니다.
관련된:
답변3
조작은 나쁜 습관이라고 생각해요여러 문자열쉘 매개변수 확장 및 변수 할당이 있습니다.
root_dir="~/songs"
for fn in */*/*.mp3
do
cp -v "$fn" "${root_dir}/${fn////-}" # replace all slashes by dashes
done
산출:
~/songs/Artist-Album-Track.mp3
답변4
배경
두 가지 목표를 달성하는 솔루션을 공식화하는 것이 가능한지 궁금합니다.
- 읽기가 더 쉽다
- 디버그하기가 더 쉽다
다음 제목의 다른 U&L Q&A에 대한 @kusalananda의 훌륭한 답변을 기반으로 합니다.-exec 옵션 이해find
, 내 생각엔 당신의 문제를 해결할 방법을 알아낸 것 같아요.
첫째, 내 예제 디렉터리 구조는 여러분의 디렉터리 구조를 모방합니다.
$ mkdir -p Artist{1..5}/Album{1..5}
$ touch Artist{1..5}/Album{1..5}/Track{1..5}.mp3
결과는 다음과 같습니다.
$ find Artist* -type f | head
Artist1/Album1/Track1.mp3
Artist1/Album1/Track2.mp3
Artist1/Album1/Track3.mp3
Artist1/Album1/Track4.mp3
Artist1/Album1/Track5.mp3
Artist1/Album2/Track1.mp3
Artist1/Album2/Track2.mp3
Artist1/Album2/Track3.mp3
Artist1/Album2/Track4.mp3
Artist1/Album2/Track5.mp3
이제 mp3 파일을 다음 위치에 복사하세요 ./targetDir
.
$ find . -type f -name '*.mp3' -exec sh -c \
'cp {} targetDir/$(echo "{}" | sed "s#\./##g;s#/#-#g")' \;
결과는 다음과 같습니다.
$ ls targetDir/ | head
Artist1-Album1-Track1.mp3
Artist1-Album1-Track2.mp3
Artist1-Album1-Track3.mp3
Artist1-Album1-Track4.mp3
Artist1-Album1-Track5.mp3
Artist1-Album2-Track1.mp3
Artist1-Album2-Track2.mp3
Artist1-Album2-Track3.mp3
Artist1-Album2-Track4.mp3
Artist1-Album2-Track5.mp3
cp ...
나는 명령을 먼저 래핑 하여 echo
작업을 제출하기 전에 출력을 확인할 수 있기 때문에 이 접근 방식을 좋아합니다 .
$ find . -type f -name '*.mp3' -exec sh -c \
'echo "cp {} targetDir/$(echo "{}" | sed "s#\./##g;s#/#-#g")"' \;
cp ./Artist1/Album1/Track1.mp3 targetDir/Artist1-Album1-Track1.mp3
cp ./Artist1/Album1/Track2.mp3 targetDir/Artist1-Album1-Track2.mp3
cp ./Artist1/Album1/Track3.mp3 targetDir/Artist1-Album1-Track3.mp3
cp ./Artist1/Album1/Track4.mp3 targetDir/Artist1-Album1-Track4.mp3
cp ./Artist1/Album1/Track5.mp3 targetDir/Artist1-Album1-Track5.mp3
cp ./Artist1/Album2/Track1.mp3 targetDir/Artist1-Album2-Track1.mp3
cp ./Artist1/Album2/Track2.mp3 targetDir/Artist1-Album2-Track2.mp3
cp ./Artist1/Album2/Track3.mp3 targetDir/Artist1-Album2-Track3.mp3
cp ./Artist1/Album2/Track4.mp3 targetDir/Artist1-Album2-Track4.mp3
...
어떻게 작동하나요?
솔루션은 다음 셸 명령의 출력을 가져온 find
후 실행됩니다.
cp {} targetDir/$(echo "{}" | sed "s#\./##g;s#/#-#g")'
cp
이렇게 하면 파일이 에서 Artist../Album../Track..
로 변경되고 targetDir/..
이름이 다시 작성되어 -
슬래시( )가 있는 곳에 대시( )가 있게 됩니다 /
.
노트:대신 사용할 경우 존재할 수 있는 접두사를 sed
먼저 제거하는 것이 좋습니다 ../
find . ...
find Artist* ..
대안?
나는 이것을 사용 find
하고 수행하는 것이 cp
여전히 이상적인 솔루션이 아니라고 생각합니다. 나는 또한 MP3 파일의 디렉토리를 관리하고 있으며 rsync
제공한 목록을 통해 비슷한 작업을 수행하는 것이 rsync
실행할 때마다 다시 복사하는 대신 업데이트하는 데 사용할 수 있으므로 장기적으로 더 유용한 구현이 될 수 있다고 생각합니다.
$ man rsync
...
--files-from=FILE read list of source-file names from FILE
그냥 생각입니다.