2017-01-25 30 views
4

Заголовок говорит все. Я сумел получить только строки с этим:Добавить wc lines в filename

lines=$(wc file.txt | awk {'print $1'}); 

Но я мог бы использовать в качестве ассистента добавления этого к имени файла. Бонусные баллы за то, что я показал, как это зацикливать на все .txt-файлы в текущем каталоге.

+3

Вы говорите о лавируя выход туалет на конце имени файла или в конце содержимого файла? [edit] ваш вопрос, чтобы включить краткий, проверяемый ввод проб и ожидаемый результат. Я поражен, что у вас есть 4 upvotes для вопроса без примера! Я видел несколько вопросов, когда люди помещали разделитель сценариев '' 's ** в скрипт ** - (' awk {'foo'} 'вместо' awk '{foo}' ') - где черт есть THAT идея, исходящая от ??? –

ответ

0

Это будет работать, но есть, безусловно, более элегантные способы.

for i in *.txt; do 
    mv "$i" ${i/.txt/}_$(wc $i | awk {'print $1'})_.txt; 
done 

Результат будет поставить номера строк хорошо перед .txt. как:

file1_1_.txt 
file2_25_.txt 
+0

Вы должны сделать цикл for с глобусом. Не трубить 'ls' – dawg

+0

Отредактировано. Благодарю. –

+0

Не могли бы вы объяснить мне причину этого? Спасибо –

0

Используйте переименовать команду

for file in *.txt; do 
lines=$(wc ${file} | awk {'print $1'}); 
rename s/$/${lines}/ ${file} 
done 
0

Вы можете использовать grep -c '^', чтобы получить количество строк, вместо wc и awk:

for file in *.txt; do 
    [[ ! -f $file ]] && continue # skip over entries that are not regular files 
    # 
    # move file.txt to file.txt.N where N is the number of lines in file 
    # 
    # this naming convention has the advantage that if we run the loop again, 
    # we will not reprocess the files which were processed earlier 
    mv "$file" "$file".$(grep -c '^' "$file") 
done 
0
#/bin/bash 

files=$(find . -maxdepth 1 -type f -name '*.txt' -printf '%f\n') 
for file in $files; do 
    lines=$(wc $file | awk {'print $1'}); 
    extension="${file##*.}" 
    filename="${file%.*}" 
    mv "$file" "${filename}${lines}.${extension}" 
done 

Вы можете настроить maxdepth соответственно.

+2

Это сломается, если в любом из файлов есть пробел или подстановочный знак в них - проблема разделения слов. – codeforester

0

вы можете сделать, как это так:

for file in "path_to_file"/'your_filename_pattern' 
    do 
     lines=$(wc $file | awk {'print $1'}) 
     mv $file $file'_'$lines 
    done 

пример:

for file in /oradata/SCRIPTS_EL/text* 
    do 
     lines=$(wc $file | awk {'print $1'}) 
     mv $file $file'_'$lines 
    done 
5
find -name '*.txt' -execdir bash -c \ 
    'mv -v "$0" "${0%.txt}_$(wc -l < "$0").txt"' {} \; 

где

  • команда bash выполняется для каждого (\;) согласованного файла ;
  • {} заменен текущим обрабатываемым именем файла и передан в качестве первого аргумента ($0) сценарию;
  • ${0%.txt} удаляет кратчайший матч от .txt из задней части строки (см. official Bash-scripting guide);
  • wc -l < "$0" печатает только количество строк в файле (см ответы на this question, например)

Пример вывода:

'./file-a.txt' -> 'file-a_5.txt' 
'./file with spaces.txt' -> 'file with spaces_8.txt' 
+0

Профессиональный внешний вид. Кроме того, только один, который использует 'wc -l'. ++ –

+1

Вы должны заменить '$ (basename" $ ​​0 ".txt)' с '$ {0% .txt}': 'basename' определенно бесполезен и неэффективен в этом случае! а также, возможно, добавить '-type f' в предикаты' find'. –

+0

@gniourf_gniourf, действительно. Благодарю. –

0
awk ' 
    BEGIN{ for (i=1;i<ARGC;i++) Files[ARGV[i]]=0 } 

    {Files[FILENAME]++} 

    END{for (file in Files) { 
     # if(file !~ "_" Files[file] ".txt$") { 

      fileF=file;gsub(/\047/, "\047\"\047\"\047", fileF) 
      fileT=fileF;sub(/.txt$/, "_" Files[file] ".txt", fileT) 

      system(sprintf("mv \047%s\047 \047%s\047", fileF, fileT)) 

     # } 
     } 
    }' *.txt 

Другой способ с AWK управлять легче второй чтобы избежать большего контроля над именем (например, избегать того, что у него уже есть счет внутри предыдущего цикла)

Из-за ошибки d замечание @gniourf_gniourf:

  • имя файла с пространством внутри возможны
  • крошечный код теперь тяжелый для такой маленькой задачи
+0

Плохой дизайн с самого начала: вы _mixing код и данные! что, если имя файла содержит цитату? –

+0

Вы правы, я забыл предположить это. Существует вторая проблема: пустые файлы, которые никогда не достигаются (используя ARGV, разрешите это, но создайте проблему с spacy names, ...) попробуйте несколько советов, но создайте фабрику gaz (модульную, но неадекватную для такого небольшого запроса). Я поставил последнюю версию с предположением до улучшения – NeronLeVelu

+0

адаптированный код для пробела и одинарной цитаты внутри имени файла – NeronLeVelu

0
{ linecount[FILENAME] = FNR } 
END { 
    linecount[FILENAME] = FNR 
    for (file in linecount) { 
     newname = gensub(/\.[^\.]*$/, "-"linecount[file]"&", 1, file) 
     q = "'"; qq = "'\"'\"'"; gsub(q, qq, newname) 
     print "mv -i -v '" gensub(q, qq, "g", file) "' '" newname "'" 
    } 
    close(c) 
} 

Сохранить выше awk сценарий в файле, говорят wcmv.awk, бег это нравится:

awk -f wcmv.awk *.txt 

Виль l Перечислите команды, которые необходимо выполнить, чтобы переименовать файлы необходимым образом (за исключением того, что он будет игнорировать пустые файлы). Чтобы их выполнить, вы можете передать вывод в оболочку для выполнения следующим образом.

awk -f wcmv.awk *.txt | sh 

Как он идет со всеми необратимыми пакетными операциями, быть внимательным и выполнять команды, только если они выглядят нормально.

+0

Плохой дизайн с самого начала: вы _mixing код и данные! _ Что, если имя файла содержит цитату? –

+0

@gniourf_gniourf Я думаю, что одинарные кавычки в именах файлов не вызовут никаких проблем сейчас. И хорошо, этот код теперь выглядит довольно приличным. : P –

1

Вы можете использовать rename команду, которая на самом деле сценарий Perl, следующим образом:

rename --dry-run 'my $fn=$_; open my $fh,"<$_"; while(<$fh>){}; $_=$fn; s/.txt$/-$..txt/' *txt 

Пример вывода

'tight_layout1.txt' would be renamed to 'tight_layout1-519.txt' 
'tight_layout2.txt' would be renamed to 'tight_layout2-1122.txt' 
'tight_layout3.txt' would be renamed to 'tight_layout3-921.txt' 
'tight_layout4.txt' would be renamed to 'tight_layout4-1122.txt' 

Если вам нравится то, что он говорит, удалить --dry-run и снова запустите.

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

Или, если вы счастливы, чтобы вызвать внешний процесс для подсчета линий, а также избегать метода Perl выше:

rename --dry-run 's/\.txt$/-`grep -ch "^" "$_"` . ".txt"/e' *txt 
+1

Проблема с 'rename' заключается в том, что она появляется во многих вариантах. Версия, которая поставляется с Perl, удобна, другие гораздо менее мощные. – hek2mgl

+1

@ hek2mgl является правильным. Например, на моей настройке Gentoo 'rename' происходит из пакета' sys-apps/util-linux' (https://www.kernel.org/pub/linux/utils/util-linux/), и это не поддержка Perl, к сожалению. Версия Perl предоставляется 'dev-perl/rename' как исполняемый файл perl-rename. –