Awk

使用 awk 將文件的符號連結列表發送到名稱中包含空格的目錄?

  • January 16, 2017

我有一個要創建軟連結的文件名列表(呼叫它filenames.txt)。使用時

cat filenames.txt | awk 'system("ln -s "$0" ~/directory\ with\ spaces/subdirectory/")`

當遇到任何帶有空格的東西(文件名或目標目錄)時,它似乎會窒息。

如何創建這些軟連結而不必先重命名所有內容以確保沒有空格?

注意:此處提供的所有範例都將從文件和文件名列表所在的目錄執行。例如,如果它們在/mnt/Hard\ Drive/some\ files/文件夾中,請確保它們filenames.txt也儲存在那裡。從 shell 執行命令時,請cd /mnt/Hard\ Drive/some\ files/然後執行範例。

AWK

AWK 的系統呼叫可以用於包含空格的項目,但它稍微複雜一些。您的原始程式碼有一些語法錯誤並且cat在那裡毫無用處。不管這個事實如何,正確的方法是先將命令建構sprintf()到變數中,然後將該變數傳遞給system(). 像這樣:

$ ls dir\ with\ spaces/                                                                                                  
$ awk '{cmd=sprintf("fpath=$(realpath -e \"%s\" );%s %s \"$fpath\" \"%s\"",$0,"ln","-s","dir with spaces/");system(cmd) }' filenames.txt                   
$ ls dir\ with\ spaces/                                                                                                  
ascii.txt@  disksinfo.txt@  input.txt@  process info.txt@

BASH(或任何類似 Bourne 的 shell)

阻力較小的路徑將通過下面給出的小 shell 腳本:

#!/bin/bash
# uncomment set -x for debugging
#set -x 

# Preferably, the directory should be full path
dir="dir with spaces/"

while IFS= read -r line
do
   if [ "x$line" != "x"  ] && [ -e "$line" ];
   then
       fpath=$( realpath -e "$line" )
       ln -s "$fpath" "$dir"
   fi
done < filenames.txt

執行中的腳本:

$ ls -l dir\ with\ spaces/                                                                                        
total 0
$ cat filenames.txt                                                                                               
input.txt
ascii.txt
disksinfo.txt
process info.txt
$ ./makelinks.sh                                                                                                  
$ ls -l dir\ with\ spaces/                                                                                        
total 0
lrwxrwxrwx 1 xieerqi xieerqi  9 1月  15 00:47 ascii.txt -> ascii.txt
lrwxrwxrwx 1 xieerqi xieerqi 13 1月  15 00:47 disksinfo.txt -> disksinfo.txt
lrwxrwxrwx 1 xieerqi xieerqi  9 1月  15 00:47 input.txt -> input.txt
lrwxrwxrwx 1 xieerqi xieerqi 16 1月  15 00:47 process info.txt -> process info.txt

它的工作方式很簡單:while IFS= read -r line; do . . . done < filenames.txt逐行讀取 filenames.txt,每個時間行都進入line變數。我們檢查該行是否不為空以及文件是否存在(此腳本將從原始文件和文件列表所在的同一目錄執行)。如果兩個條件都為真,我們就建立連結。

請注意,您應該確保文件以換行符結尾 - 如果最後一行不以換行符結尾(確實發生),則將跳過最後一行,因此不會為該文件建立任何連結.

儘管不理想且並非沒有怪癖,但對於 awksystem()不可用的情況(這在當今可能很少見),這是一個可行的解決方案。

xargs

一個稍微簡單的 shell 方法是通過xargsand bash -c '' sh,我們再次讀取 filenames.txt ,使用標誌逐行讀取-L1,並將每一行用作 bash 的參數。使用$@我們獲取整個命令行參數數組( $ 1, $ 2,3美元。. . 等)並變成字元串變數,然後將其傳遞給ln. 最後sh是設置$0變數。是否有必要這樣做是有爭議的,但這不是這個問題的主題,因此讓我們跳過它:)

$ xargs -I {} -L1 bash -c 'file="$@";fpath=$(realpath -e "$file"); ln -s "$fpath"  ./dir\ with\ spaces/"$file" ' sh < filenames.txt                      
$ ls dir\ with\ spaces/                                                                                                  
ascii.txt@  disksinfo.txt@  input.txt@  process info.txt@

Python

$ ls dir\ with\ spaces/ 
$ python -c "import os,sys;fl=[f.strip() for f in sys.stdin];map(lambda x: os.symlink(os.path.realpath(x),'./dir with spaces/' + x),fl)" < filenames.txt
$ ls dir\ with\ spaces/                                                                                                  
ascii.txt@  disksinfo.txt@  input.txt@  process info.txt@

它的工作方式很簡單——我們重定向filenames.txt到 pythonstdin中,將每一行讀入 list fl,然後為 listos.symlink()中的每個項目執行。冗長的單線,但有效。

Perl

更短的版本是通過 Perl 實現的:

$ perl -lane 'use Cwd "realpath";symlink(realpath($_),"./dir with spaces/" . $_)' < filenames.txt                                                     
$ ls dir\ with\ spaces/                                                                                                  
ascii.txt@  disksinfo.txt@  input.txt@  process info.txt@

引用自:https://unix.stackexchange.com/questions/337504