Xargs для извлечения имени файла

Плагиат кода из ответа, на который вы ссылаетесь, и повышение его надежности:

for file in *; do mv "$file" "$(echo "$file" | tr '_' ' ')" ; done

Цитирование гарантирует, что каждое имя файла передается в mv как единое токен, а не разбивается на границах пространства.

Если у вас есть доступ к утилите переименования на основе Perl, следующая также будет работать:

rename -n 's/_/ /g' *

(Удалите переключатель -n после подтверждения, что предварительный просмотр соответствует {{ 1}} на то, что вы хотели бы сделать.)

3
05.09.2018, 05:18
3 ответа

Не анализировать ls .
Вам не нужно xargsдля этого, вы можете использовать find -exec.

попробуй это,

find. -maxdepth 1 -type f -name "*.html" -exec \
    sh -c 'f=$(basename "$1"); echo "[${f%.*}]($1)" >> index.md' sh {} \;

Если вы хотите, чтобы использовал xargs, используйте очень похожую версию:

find. -maxdepth 1 -type f -name "*.html" -print0 | \
    xargs -0 -I{} sh -c 'f=$(basename "$1"); echo "[${f%.*}]($1)" >> index.md' sh {} \;

Другой способ без запуска xargsили-exec:

find. -maxdepth 1 -type f -name "*.html" -printf '[%f](./%f)\n' \
    | sed 's/\.html\]/]/' \
    > index.md
9
27.01.2020, 21:07

Просто сделай:

for f in *.html; do printf '%s\n' "[${f%.*}](./$f)"; done > index.md

Используйте set -o nullglob(zsh,yash)илиshopt -s nullglob(bash)для *.html, чтобы раскрыть ничего вместо*.html(или сообщить об ошибке в zsh), когда нет htmlфайла. С zshвы также можете использовать *.html(N)или в ksh93~(N)*.html.

Или одним printfзвонком сzsh:

files=(*.html)
rootnames=(${files:r})
printf '[%s](./%s)\n' ${basenames:^files} > index.md

Обратите внимание, что в зависимости от используемого синтаксиса уценки вам может потребоваться HTML -кодировать часть title , а URI -кодировать часть URI, если имена файлов содержат некоторые проблемные персонажи. Несоблюдение этого требования может даже привести к появлению формы уязвимости XSS в зависимости от контекста. с кш93,вы можете сделать это с помощью:

for f in *.html; do
  title=${ printf %H "${file%.*}"; }
  title=${title//$'\n'/"<br/>"}
  uri=${ printf '%#H' "$file"; }
  uri=${uri//$'\n'/%0A}      
  printf '%s\n' "[$title]($uri)"
done > index.md

Где %H¹ определяет кодировку HTML, а %#Hкодировку URI, но нам по-прежнему нужно обращаться к символам новой строки отдельно.

Или сperl:

perl -MURI::Encode=uri_encode -MHTML::Entities -CLSA -le '
  for (<*.html>) {
     $uri = uri_encode("./$_");
     s/\.html\z//;
     $_ = encode_entities $_;
     s:\n:<br/>:g;
     print "[$_]($uri)"
  }'

Использование <br/>для символов новой строки. Вместо этого вы можете использовать ␤ или, в более общем случае, выбрать какую-либо форму альтернативного представления для непечатаемых символов -.

В вашем коде есть несколько ошибок:

  • анализ выводаls
  • используйте $как литерал внутри двойных кавычек
  • Использование awkдля чего-то, что grepможет сделать (само по себе не неправильно, но излишне)
  • используйте xargs -0, когда ввод не является NUL -разделителем
  • -Iконфликтует с -L 1. -L 1запускает одну команду на строку ввода, но каждое слово в строке передается как отдельные аргументы, тогда как -I @@запускает одну команду для каждой строки ввода с полной строкой (за вычетом завершающих пробелов и заключением в кавычки. все еще обрабатывается )используется для замены @@.
  • использование {}внутри кода аргументаsh(уязвимость внедрения команд)
  • В shvarв ${var%.*}— это имя переменной , оно не будет работать с произвольным текстом.
  • используйте echoдля произвольных данных.

Если вы хотите использовать xargs -0, вам понадобится что-то вроде:

printf '%s\0' * | grep -z '\.html$' | xargs -r0 sh -c '
  for file do
    printf "%s\n" "[${file%.*}](./$file)"
  done' sh > file.md
  • Замена lsна printf '%s\0' *для получения вывода с разделителями NUL -
  • awkсgrep -z(расширением GNU )для обработки этого вывода с разделителями NUL -
  • xargs -r0(Расширения GNU )без каких-либо -n/ -L/ -I, потому что, пока мы создаем sh, мы могли бы также обработать как можно больше файлов
  • заставить xargsпередать слова в качестве дополнительных аргументов в sh(, которые становятся позиционными параметрами внутри встроенного кода ),не внутри аргумента кода.
  • , что означает, что мы можем более легко хранить их в переменных (здесь с for file do, который по умолчанию перебирает позиционные параметры ), поэтому мы можем использовать оператор раскрытия параметров ${param%pattern}.
  • используйте printfвместо echo.

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


¹ Кажется, он не работает должным образом для многобайтовых символов в моей версии ksh93, хотя (ksh93u+ в системе GNU)

13
27.01.2020, 21:07

Вам действительно нужно xargs?

ls *.html | perl -pe 's/.html\n//;$_="[$_](./$_.html)\n"'

(Если у вас более 100000 файлов):

printf "%s\n" *.html | perl -pe 's/.html\n//;$_="[$_](./$_.html)\n"'

или (медленнее, но короче):

for f in *.html; do echo "[${f%.*}](./$f)"; done
1
27.01.2020, 21:07

Теги

Похожие вопросы