Как я могу применить `cut` к нескольким файлам, а затем« вставить »результаты?

Я часто делаю операции вроде

paste <(cut -d, -f1 file1.csv) <(cut -d, -f1 file2.csv) 

который очень утомительный с более чем несколькими файлами.

Могу ли я автоматизировать этот процесс, например, с помощью globbing? Я могу сохранить результаты cut с помощью

 typeset -A cut_results for f in file*.csv; do cut_results[$f]="$(cut -d, -f1 $f)" done 

но я не уверен, как исходить оттуда.

  • zsh завершение по истории не работает
  • Что случилось с ~ обновлением oh-my-zsh?
  • Запустите git fetch после любой команды cd
  • Скрытие завершения zsh
  • обмена или синхронизации истории между Zsh и Bash
  • Как управлять mysql с помощью zpty?
  • zsh уведомление об электронной почте (в maildir)
  • Выход из терминала «nohup ./my_script &» => «У вас есть рабочие задания». ОК, чтобы выйти?
  • 7 Solutions collect form web for “Как я могу применить `cut` к нескольким файлам, а затем« вставить »результаты?”

    Вы можете автоматизировать это с помощью globbing, в частности, для определения e glob , плюс eval , но это некрасиво, и цитата сложна:

     eval paste *.csv(e\''REPLY="<(cut -d, -f1 $REPLY)"'\') 
    • Часть между \'…\' – это некоторый код для выполнения для каждого соответствия шара. Он выполняется с переменной REPLY установленной в соответствие, и может ее модифицировать.
    • Я помещаю код в одинарные кавычки, чтобы он не расширялся при анализе glob.
    • Код REPLY="<(cut -d, -f1 $REPLY)" генерирует строку <(cut -d, -f1 file1.csv) если совпадение – file1.csv . Двойные кавычки необходимы, чтобы часть после знака равенства не расширялась при выполнении кода e кроме подстановки значения REPLY .
    • Поскольку каждый файл globbed заменяется на строку,

    Было бы лучше скрыть сложность функции. Минимально проверены.

     function map { emulate -LR zsh local cmd pre cmd=() while [[ $# -ne 0 && $1 != "--" ]]; do cmd+=($1) shift done if ((!$#)); then echo >&2 "Usage: $0: COMMAND [ARGS...] -- PREPROCESSOR [ARGS...] -- FILES..." return 125 fi shift while [[ $# -ne 0 && $1 != "--" ]]; do pre+="${(q)1} " shift done if ((!$#)); then echo >&2 "Usage: $0: COMMAND [ARGS...] -- PREPROCESSOR [ARGS...] -- FILES..." return 125 fi shift eval "${(@q)cmd}" "<($pre${(@q)^@})" } 

    Пример использования (синтаксис напоминает zargs ):

     map paste -- cut -d, -f1 -- *.csv 

    Попробовать awk

     awk '{L[FNR]=L[FNR] $1 "\t"}END{for(i=1;i<=FNR;i++)print L[i]}' *.csv 

    или вставить с помощью sed

     paste *.csv | sed 's/ [^\t]*//g' 

    Я думаю, что ваша первая строка примерно так же хороша, как и для простого однострочного.

    Если есть множество файлов со всеми разными именами, вы можете уменьшить повторяющуюся типизацию с помощью простого расширения истории «чит»:

    Первый запуск <(cut -d, -f1

    Обратите внимание на конечное пространство. Также обратите внимание, что эта команда даст вам дополнительную подсказку; просто нажмите Ctrl- C . Единственный момент – добавить его в историю.

    Далее запустите paste !!file1.csv) !!file2.csv)

    !! будет расширяться до полного содержимого предыдущего запуска команды, включая конечное пространство. Обратите внимание: если вы забудете закрывающиеся круглые скобки, вы получите вторичное приглашение; вы можете просто набрать Ctrl- C и повторить попытку, если это произойдет.

    Это немного взломано, но достаточно хорошо для одноразового использования. Если вы делаете это много, вы можете написать функцию bash.

    Я bash скрипты bash в настоящий момент, и это казалось отличной простой задачей для практики, поэтому я написал следующее. (Мой другой ответ дает простой взлом для расширения истории, но это полный скрипт, и я счел его достойным получения дополнительного ответа.) Я считаю, что это совместимо с POSIX и должно работать с #!/bin/sh , но не на 100% конечно. EDIT: На самом деле, =~ не совместим с POSIX. Вы могли бы взять этот чек и позволить cut вернуть ошибку.

     #!/bin/bash fieldtocut=1 delimiter=',' usage () { cat << EOF usage: $0 [-f FIELD] [-d DELIMITER] file1.. Cuts field FIELD from each file and pastes it. Default field is 1, default delimiter is ',' EOF exit $1 } while getopts ':f:d:' opt ; do case $opt in f) if [[ $OPTARG =~ ^[0-9]+$ ]] ; then fieldtocut="$OPTARG" else usage 1 fi ;; d) delimiter=$OPTARG ;; *) usage 1 ;; esac done shift $((OPTIND-1)) [ $# -eq 0 ] && usage 0 pasteargs='' for file in "$@" ; do pasteargs=$(printf '%s' "$pasteargs" '<(cut -d$delimiter -f$fieldtocut ' "$file" ') ') done eval paste $pasteargs 

    Предполагая, что ваши аргументы находятся в "$@" , я верю что-то вроде:

     eval "paste $(printf "<( cut -d, -f1 %q ) " "$@")" 

    должен это сделать.

    Вот еще один способ сделать это, что очень похоже на ответ от Wildcard :

     files=( file1.csv file2.csv) eval paste "<( cut -d, -f1 ${^files[@]} )" 

    Вместо цикла for используется расширение ${^ ... } которое является Zsh-специфичным.

    Сначала должны быть назначены files причин, так что globbing всегда выполняется последним, поэтому если files необходимо сгенерировать автоматически (как в files=( *.csv ) ), то что-то вроде ${^:-( *.csv )} будет расширяться только после того, как все другие расширения произошли. Мы хотим, чтобы он расширился первым .

    Расширение ${^ ... } заставляет результирующий массив действовать как результат расширения скобки. Например, присвойте x=(ab) а затем сравните echo ${x}y с echo ${^x}y .

    Цитирование необходимо обмануть Zsh для обработки окружающего текста, как буквальная строка. В противном случае он разделил бы командную строку в пространствах, поэтому наше расширение ${^ ... } уменьшилось бы до ""${^ ... }"" ; то есть каждый элемент будет окружен пустой строкой. То есть,

     echo "<( cut -d, -f1 ${^files[@]} )" 

    а также

     echo "<( cut -d, -f1 "\ ${^files[@]}\ " )" 

    эквивалентны, но не совпадают с

     echo <( cut -d, -f1 ${^files[@]} ) 

    Но цитирование вводит новую проблему: командная строка анализируется и разделяется без учета расширения. То есть, хотя мы эффективно вошли

     paste <( cut -d, -f1 file1.csv ) <( cut -d, -f1 file2.csv ) 

    по желанию, это фактически анализируется как

     paste '<( cut -d, -f1 file1.csv )' '<( cut -d, -f1 file2.csv )' 

    Поэтому нам нужно eval для повторного анализа правильно сформированного выражения. Чтобы увидеть это в действии, сравните

     setopt noxtrace eval paste "<( cut -d, -f1 ${^files[@]} )" 1>/dev/null 2>&1 

    в

     setopt xtrace eval paste "<( cut -d, -f1 ${^files[@]} )" 1>/dev/null 2>&1 

    Я надеялся, что некоторая комбинация вложенных расширений, расширение ${ ... :- ... } и флаги расширения параметров Q , z и / или s приведут к переоценке без eval , но, очевидно, это не дело. Я также хочу, чтобы был способ заставить глотать, но опять же это кажется невозможным.

    Вы можете получить awk чтобы перебирать файлы в lockstep и сообщать интересующее поле из каждого файла. Поместите этот код в файл, скажем cut_files.awk

     NR == FNR{printf "%s%s",$1, FS; for (k=2; k<ARGC; ++k) {getline < ARGV[k]; printf "%s%s", $1, k==ARGC-1?"\n":FS}; next}; NR != FNR{for (k=2; k<ARGC; ++k) close(ARGV[k]); exit} 

    И тогда назовите его так

     awk -F',' -f cut_files.awk file1 file2 file3 file4 .... 
    Interesting Posts

    Как восстановить или восстановить удаленные файлы в ubuntu linux

    Установка Linux в LiveCD?

    Установите новый дистрибутив Linux без перезагрузки GRUB2

    Является ли архивирование всей файловой системы из корня эффективной стратегией резервного копирования?

    Настройки DPI в Awesome window manager

    Поведение команды `du` с флагом` -L`

    буфер обмена в bash

    Невозможно изменить / удалить файлы через долю samba

    Обновление win10 изменило разделы mint на разделы ms … теперь что

    Debian 7: Gnome3 иногда останавливается при загрузке

    Отключение управления питанием

    Является ли xinetd еще лучшим методом, позволяющим нон-корневым демонам прослушивать привилегированные порты?

    Низкая (?) Энтропия доступна в Arch Linux?

    Получить Debian Wheezy netinstall для обнаружения wlan

    Пересечение строк в файле с использованием bash и переход к переменной. Результирующая переменная – это не то же значение, что и файл, почему?

    Linux и Unix - лучшая ОС в мире.