I need help using xargs(1) and bc(1) in the same line. I can do it multiple lines, but I really want to find a solution in one line.

Here is the problem: The following line will print the size of a file.txt

ls -l file.txt | cut -d" " -f5

And, the following line will print 1450 (which is obviously 1500 - 50)

echo '1500-50' | bc

Trying to add those two together, I do this:

ls -l file.txt | cut -d" " -f5 | xargs -0 -I {} echo '{}-50' | bc

The problem is, it's not working! :)

I know that xargs is probably not the right command to use, but it's the only command I can find who can let me decide where to put the argument I get from the pipe.

This is not the first time I'm having issues with this kind of problem. It will be much of a help..

Thanks

有帮助吗?

解决方案

If you do

ls -l file.txt | cut -d" " -f5 | xargs -0 -I {} echo '{}-50'

you will see this output:

23
-50

This means, that bc does not see a complete expression.

Just use -n 1 instead of -0:

ls -l file.txt | cut -d" " -f5 | xargs -n 1 -I {} echo '{}-50'

and you get

23-50

which bc will process happily:

ls -l file.txt | cut -d" " -f5 | xargs -n 1 -I {} echo '{}-50' | bc
-27

So your basic problem is, that -0 expects not lines but \0 terminated strings. And hence the newline(s) of the previous commands in the pipe garble the expression of bc.

其他提示

This might work for you:

ls -l file.txt | cut -d" " -f5 | sed 's/.*/&-50/' | bc

Infact you could remove the cut:

ls -l file.txt | sed -r 's/^(\S+\s+){4}(\S+).*/\2-50/' | bc

Or use awk:

ls -l file.txt | awk '{print $5-50}'

Parsing output from the ls command is not the best idea. (really).

you can use many other solutions, like:

find . -name file.txt -printf "%s\n"

or

stat -c %s file.txt

or

wc -c <file.txt

and can use bash arithmetics, for avoid unnecessary slow process forks, like:

find . -type f -print0 | while IFS= read -r -d '' name
do
        size=$(wc -c <$name)
        s50=$(( $size - 50 ))
        echo "the file=$name= size:$size minus 50 is: $s50"
done

Here is another solution, which only use one external command: stat:

file_size=$(stat -c "%s" file.txt) # Get the file size
let file_size=file_size-50         # Subtract 50

If you really want to combine them into one line:

let file_size=$(stat -c "%s" file.txt)-50

The stat command gets you the file size in bytes. The syntax above is for Linux (I tested against Ubuntu). On the Mac the syntax is a little different:

let file_size=$(stat -f "%z" mini.csv)-50
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top