удалить возврат каретки в скрипте bash или игнорировать его при использовании mv / mkdir

#bash #ubuntu #grep #line-endings

#bash #ubuntu #grep #окончания строк

Вопрос:

Я пытаюсь создать каталог из переменной, которая поступает из grep-ing, и он продолжает давать сбой, сообщая мне, что возврат каретки есть там, где его нет. Я пробовал dos2unix, он сообщает мне, что это недопустимый файл. Я создал скрипт в ubuntu 10.10 с использованием окончаний строк gedit и unix.

Я также попытался передать вывод файла cat’d в

 tr -d 'r'
  

это не поможет.

вот часть скрипта, в которой произошел сбой:

 ARTIST=`cat read | grep DTITLE | cut -c8- | cut -d"/" -f 1`
ALBUM=`cat read | grep DTITLE | cut -c8- | cut -d"/" -f 2 | awk '{gsub(/^[ t] |[t] $/,"")};1'`
mkdir $DEST/"$ARTIST"
cd $DEST/"$ARTIST"
mkdir "$ALBUM"
mv $DEST/temp/*.flac $DEST/"$ARTIST"/"$ALBUM"/
  

и ошибка, которую я получаю:

 mv: target `Hardr' is not a directory
  

вот файл «read», из которого он извлекается:

 macmini:~/Dropbox/bin$ cat ~/Desktop/temp/read
210 folk 0d021f02 CD database entry follows (until terminating `.')
# xmcd CD database file
#
# Track frame offsets:
#   150
#   13002
#
# Disc length: 545 seconds
#
# Revision: 0
# Processed by: cddbd v1.5.2PL0 Copyright (c) Steve Scherf et al.
# Submitted via: CDex 1.50Beta7
#
DISCID=0d021f02
DTITLE=Cursive / Art is Hard
DYEAR=2003
DGENRE=Indie
TTITLE0=Art is Hard
TTITLE1=Sinner's Serenade
EXTD= YEAR: 2003
EXTT0=
EXTT1=
PLAYORDER=
.
  

на этом этапе я немного заблудился. откуда берется возврат каретки?

Комментарии:

1. Вы уверены, что версия запущенного вами скрипта соответствует той, которую вы опубликовали? Сообщение об ошибке выглядит так, как будто оно исходит из скрипта без двойных кавычек $ALBUM в аргументе mv .

Ответ №1:

Я думаю, что это происходит из прочитанного файла. Запустите dos2unix этот файл.

Однако это сообщение об ошибке подчеркивает другую проблему: mv неверно интерпретирует то, что вы ему даете, потому что то, что он считает целевым, слишком короткое. Я предполагаю, что вы неправильно указываете пути к файлам, содержащие пробелы. Попробуйте заключить весь аргумент в двойные кавычки, а не только его компоненты.

Комментарии:

1. Да, всегда нужно заключать переменные имени файла в двойные кавычки в bash. Распространенная ошибка.

2. Если скрипт был запущен, как показано, это не проблема. $DEST/"$ARTIST"/"$ALBUM"/ точно так же, как $DEST"/$ARTIST/$ALBUM/" или как "$DEST/$ARTIST/$ALBUM/" , если в $DEST нет никаких специальных символов. Сообщение об ошибке показывает, что $ALBUM было разделено и после него не было / .

3. ах, это имеет больше смысла. я пытался разделить «исполнитель / альбом» на отдельные переменные для обоих, используя cut. я думал, что это то, что вырезает -d»/» -f 2 и cut -d»/» -f 1, вырезает все до, а затем все после «/»

4. я собираюсь отметить это как ответ, поскольку запуск dos2unix в этом файле решил проблему. не так элегантно, как хотелось бы, но я не знаю, как / почему в этом файле есть возврат каретки, так что это сработает. если у кого-нибудь есть какие-либо идеи, почему у него это есть, пожалуйста, дайте мне знать.

5. у кого-нибудь есть идеи, почему это вставляет возврат каретки? я бы хотел удалить зависимость от dos2unix.

Ответ №2:

Вы можете сделать это с помощью одного awk-скрипта

 #!/bin/bash   

awk -F"[/=]" 'BEGIN{
    qq="47"
    DEST="/tmp"
}/DTITLE/{
    ARTIST=$2
    ALBUM=$NF
    gsub(/^[ t] |[ t] $/,"",ALBUM)
    gsub(/^[ t] |[ t] $/,"",ARTIST)
    cmd="mkdir "qq DEST"/"ARTIST qq
    print cmd
    #system(cmd)
    cmd="mkdir -p " qq DEST"/"ARTIST  "/" ALBUM qq
    print cmd
    #system(cmd)
    cmd="mv "DEST"/temp/*.flac " qq DEST"/"ARTIST  "/" ALBUM qq
    print cmd
    #system(cmd)
} ' file
  

Чтобы запустить его, сохраните как сценарий оболочки (например myscript.sh ) и введите ./myscript.sh в командной строке

Или вы можете использовать язык программирования, который решает проблемы с громоздкими кавычками оболочки, например, скрипт Ruby (1.9 )

 #!/usr/bin/env ruby  
require 'fileutils'
DEST="/tmp"
File.open("file") do |f|
    while not f.eof?
        line = f.gets.chomp
        if line[/DTITLE/]
            line = line.split(/[/=]/)
            ARTIST=line[1].strip
            ALBUM=line[2].strip
            Dir.mkdir( File.join(DEST, ARTIST) )
            Dir.mkdir( File.join(DEST, ARTIST, ALBUM) )
            Dir.glob( File.join(DEST, "temp", "*.flac") ).each do |file|
                FileUtils.mv ( file, File.join(DEST, ARTIST, ALBUM) )
            end
        end
    end
end
  

Чтобы запустить его, сохраните как (например, myscript.rb ) и введите ruby myscript.rb в командной строке или внутри сценария оболочки.

Комментарии:

1. вау, это здорово. не могу дождаться, чтобы попробовать это сегодня вечером. возможно, это глупый вопрос, но есть ли способ использовать 2 разных интерпретатора в одном скрипте? я полагаю, что нет, так что я должен вызвать это из другого скрипта или я должен переписать это на ruby?

2. Вы бы использовали оболочку для выполнения скриптов. Если вы хотите использовать awk решение, просто скопируйте и вставьте и сохраните его как сценарий оболочки и запустите в обычном режиме. Если вы решите использовать Ruby, то используйте интерпретатор ruby для запуска скрипта. например, введите ruby myscript.rb в командной строке.